用于打印枚举的模板化流操作符

时间:2011-10-07 14:09:36

标签: 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: 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;
}

3 个答案:

答案 0 :(得分: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的任何类型都会考虑重载,但是对于所有其他类型都会被忽略,从而防止出现一系列模糊的重载错误。

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