我有一个命名空间,可以通过我的应用程序创建一系列枚举,并使用相关的打印语句,如下所示:
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;
}
答案 0 :(得分:3)
显而易见的方法将导致所有类型都考虑过载;这将导致所有类型的调用都不明确,因为模板不是挑剔的。因此,您需要某种方式告诉编译器您的enum
是enum
的正确类型,并忽略所有其他内容;特质课可能是最简单的方法。
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
的任何类型都会考虑重载,但是对于所有其他类型都会被忽略,从而防止出现一系列模糊的重载错误。
答案 1 :(得分: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。
答案 2 :(得分: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;
}