Реализация is_enum - программирование

Реализация is_enum

Я пытаюсь реализовать std::is_enum. Вот мой код:

template<typename T>
struct is_enum {
    static bool value;
};

template<typename T>
bool is_enum<T>::value = false;

template<enum E>
struct is_enum {
    static bool value;
};

template<enum E>
bool is_enum<E>::value = true;

Этот код вызывает ошибку. Точнее:

g++ -std=c++0x -Wall -o "enum2" "enum2.cpp" (in directory: /home/aristophanes/Desktop/C++)
Compilation failed.
enum2.cpp:11:15: error: use of enum ‘E’ without previous declaration
enum2.cpp:3:10: error: template parameter ‘class T’
enum2.cpp:12:8: error: redeclared here as ‘int E’
enum2.cpp:16:15: error: use of enum ‘E’ without previous declaration
enum2.cpp:17:14: error: ‘E’ was not declared in this scope
enum2.cpp:17:15: error: template argument 1 is invalid
enum2.cpp:17:18: error: template declaration of ‘bool value’

Может кто-нибудь объяснить мне, где я ошибаюсь? Это моя или ошибка компилятора? Спасибо заранее.

Изменить:, если это совершенно неправильно, то как я могу его исправить?

Примечание: Я использую g++ -o <file> <file>.cpp

4b9b3361

Ответ 1

Лучший способ реализовать это - использовать магию компилятора, и я считаю, что большинство реализаций делают это.

Например, здесь реализация libС++ для gcc >= 4.3 и любого компилятора, что __has_feature(is_enum) 1

template <class _Tp> struct _LIBCPP_VISIBLE is_enum
    : public integral_constant<bool, __is_enum(_Tp)> {};



Для всех других компиляторов libС++ делает:

template <class _Tp> struct _LIBCPP_VISIBLE is_enum
    : public integral_constant<bool, !is_void<_Tp>::value             &&
                                     !is_integral<_Tp>::value         &&
                                     !is_floating_point<_Tp>::value   &&
                                     !is_array<_Tp>::value            &&
                                     !is_pointer<_Tp>::value          &&
                                     !is_reference<_Tp>::value        &&
                                     !is_member_pointer<_Tp>::value   &&
                                     !is_union<_Tp>::value            &&
                                     !is_class<_Tp>::value            &&
                                     !is_function<_Tp>::value         > {};

Некоторые из этих черт другого типа по-прежнему требуют магии компилятора. 2. is_union. Однако это условие можно переписать так, что ему не нужна магия компилятора. Это можно сделать, заменив отдельные проверки для объединений и классов с помощью одной проверки для обоих, как указывает Йоханнес Шауб.

<суб > 1. Насколько я знаю, только clang реализует __has_feature, к сожалению.
<Суб > 2. Интересно, что libС++ имеет версию is_union<T> и is_class<T>, которые не используют встроенные функции компилятора, но в результате они дают ошибочные результаты для типов union. Но их ошибочные результаты являются взаимодополняющими, поэтому реализация резервного копирования libС++ is_enum<T> обеспечивает точные результаты.

Ответ 2

Это

template<enum E>

promises, что аргумент шаблона является значением типа enum E. Аргумент НЕ является типом (аргументы типа шаблона вводятся typename или для обратной совместимости, class. Даже struct не разрешено). Это просто как сказать

template<int i>

кроме имени для переменной не указывается.

Дела идут не так.

Ответ 3

Проблема заключается в том, что

template<enum E>

интерпретируется как неназванный параметр с типом forward объявленного перечисления с именем E.
Семантически то же самое для

template<int>

Просто подставив int в enum E.