C++ 用于打印枚举的模板化流运算符

C++ 用于打印枚举的模板化流运算符,c++,templates,C++,Templates,我有一个名称空间,用于创建一系列枚举,这些枚举通过我的应用程序与相关的打印语句一起使用,如下所示: 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: re

我有一个名称空间,用于创建一系列枚举,这些枚举通过我的应用程序与相关的打印语句一起使用,如下所示:

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;
}

显而易见的方法将导致您的过载被认为是所有类型;这将导致对所有类型的调用都不明确,因为模板是不可选择的。因此,您需要某种方法告诉编译器您的
enum
是正确的
enum
类型,并忽略所有其他类型;traits类可能是最简单的方法

namespace NS {
  enum EnumA { };

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

  template<>
  struct is_ns_enum<EnumA> : std::true_type { };
}
NS{
enum EnumA{};
模板
结构是_ns_enum:std::false_type{};
模板
结构是_ns_enum: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&) {
  ...
}
模板
内联类型名称std::enable_if::type

运算符如果您也对流类型进行模板化,这将起作用:

#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;
}
#包括
#包括
使用名称空间std;
名称空间NS{
enum EnumA{A1,A2,A3};
enum EnumB{B1,B2,B3};
内联标准::字符串到字符串(常量枚举键){
开关(钥匙){
案例A1:返回“A1”;
案例A2:返回“A2”;
案例A3:返回“A3”;
}
返回“未知”;
}
内联标准::字符串到字符串(常量枚举键){
开关(钥匙){
案例B1:返回“B1”;
案例B2:返回“B2”;
案例B3:返回“B3”;
}
返回“未知”;
}
};
模板

内联std::ostream&operator如果名称空间
NS
中只有支持toString的类型,您可以将
运算符+1放在似乎有效的位置,但是,我最终编写了同样数量的代码,我总是忘记编写,因此需要一个模板。我不知道如何工作,但它确实有效,特别是因为直接打印到流不起作用(即使它在名称空间中)。
#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;
}
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;
  }

}