2011-10-07 54 views
3

我有一個創建了一系列通過我的應用程序與相關聯的打印語句中使用枚舉的命名空間,像這樣模板化流運算符:打印枚舉

namespace NS { 
    enum EnumA { A1, A2, A3 }; 
    enum EnumB { B1, B2, B3 }; 

    inline std::string toString(const EnumA key) { 
     switch(key) { 
     case A1: return "A1"; 
     case A2: return "A2"; 
     case A3: return "A3"; 
     } 
     return "UNKNOWN"; 
    } 

    // .. same for EnumB 
} 

// this is the part I would like to templatize 
inline std::ostream& operator<<(std::ostream& s, const NS::EnumA key) { 
    s << NS::toString(key); 
    return s; 
} 
inline std::ostream& operator<<(std::ostream& s, const NS::EnumB key) { 
    s << NS::toString(key); 
    return s; 
} 

是否有可能模板化的流運算符與任何合作NS枚舉,所以我只需要有一個?像:

template <typename T> 
inline std::ostream& operator<<(std::ostream& s, const NS::<T> key) { 
    s << NS::toString(key); 
    return s; 
} 

回答

2

如果在命名空間NS的唯一的東西是的ToString能力的類型,你可以把你的operator<<在命名空間中,正是如此:

namespace NS { 
    enum EnumA { A1, A2, A3 }; 
    enum EnumB { B1, B2, B3 }; 

    inline std::string toString(const EnumA key) { 
    ... 
    } 
    inline std::string toString(const EnumB key) { 
    ... 
    } 

    template <typename T> 
    inline std::ostream& operator<<(std::ostream& s, const T key) { 
    std::operator << (s, NS::toString(key)); 
    return s; 
    } 

} 

完整的程序是here

+0

我不知道這是如何工作的,但它確實如此,特別是因爲直接打印到流中不起作用(即使它在名稱空間中)。 – steveo225

3

顯而易見的方法會導致所有類型的負載被考慮;這將導致調用對於所有類型都是不明確的,因爲模板並不挑剔。所以你需要一些方法來告訴編譯器你的enumenum的正確類型,並且忽略所有其他的;特質類可能是最簡單的方法。

namespace NS { 
    enum EnumA { }; 

    template<typename T> 
    struct is_ns_enum : std::false_type { }; 

    template<> 
    struct is_ns_enum<EnumA> : std::true_type { }; 
} 

從那裏,你可以使用SFINAE來實現你的功能。

template<typename T> 
inline typename std::enable_if<is_ns_enum<T>::value, std::ostream&>::type 
operator <<(std::ostream& s, const T&) { 
    ... 
} 

這樣,過載被認爲是你的專業is_ns_enum任何類型,但被丟棄對於所有其他類型,防止超載含糊不清的錯誤,擺率。

+0

+1這似乎工作,但是,我最終寫了相同數量的代碼,我總是忘記做,因此想要一個模板。 – steveo225

0

如果模板化的流類型爲好,這將工作:

#include <string> 
#include <iostream> 
using namespace std; 

namespace NS { 
    enum EnumA { A1, A2, A3 }; 
    enum EnumB { B1, B2, B3 }; 

inline std::string toString(const EnumA key) { 
     switch(key) { 
     case A1: return "A1"; 
     case A2: return "A2"; 
     case A3: return "A3"; 
     } 
     return "UNKNOWN"; 
    } 

inline std::string toString(const EnumB key) { 
     switch(key) { 
     case B1: return "B1"; 
     case B2: return "B2"; 
     case B3: return "B3"; 
     } 
     return "UNKNOWN"; 
    } 
}; 

template <class Stream, typename T> 
inline std::ostream& operator<<(Stream& s, T key) { 
    s << NS::toString(key); 
    return s; 
} 

int main() 
{ 
    cout << NS::A2; 
    cout << NS::B3; 
}