Оператор Templatize для печати перечислений - PullRequest
3 голосов
/ 07 октября 2011

У меня есть пространство имен, которое создает серию перечислений, используемых в моем приложении со связанными операторами печати, например:

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 ]

3 голосов
/ 07 октября 2011

Очевидный подход приведет к тому, что ваша перегрузка будет учтена для всех типов; это приведет к неоднозначности вызовов для всех типов, поскольку шаблоны не являются разборчивыми. Таким образом, вам нужен какой-то способ сообщить компилятору, что ваш 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, но отбрасывается для всех других типов, предотвращая множество неоднозначных ошибок перегрузки.

2 голосов
/ 07 октября 2011

Если в пространстве имен 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;
  }

}

Полная программа здесь .

0 голосов
/ 07 октября 2011

Если вы также шаблонизируете тип потока, это будет работать:

#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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...