20

を実装しようとしています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

4

3 に答える 3

18

これを実装する最善の方法は、コンパイラ マジックを使用することです。私は、ほとんどの実装がこれを行っていると信じています。

たとえば、gcc >= 4.3 および__has_feature(is_enum)1のコンパイラに対する libc++ の実装は次のとおりです。

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



他のすべてのコンパイラでは、libc++ は次のことを行います。

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。ただし、その条件は、コンパイラの魔法を必要としないように書き換えることができます。これは、Johannes Schaub が指摘するように、共用体とクラスの個別のチェックを両方の単一のチェックに置き換えることで実行できます。

__has_feature1.残念ながら、私が知る限り、実装はclangだけです。
2. 興味深いことに、libc++ にはコンパイラ組み込み関数を使用しない と のバージョンがis_union<T>ありis_class<T>ますが、その結果、union 型に対して誤った結果を提供します。しかし、それらの誤った結果は補完的なものであるため、libc++ のフォールバック実装is_enum<T>は正確な結果を提供します。

于 2012-07-03T19:00:17.687 に答える
9

これ

template<enum E>

テンプレート引数が型のenum Eであることを約束します。引数は型ではありません(型テンプレート引数は、によってtypename、または下位互換性のために導入されていclassます。さらにstructは許可されていません)。言っているようなものです

template<int i>

変数に名前が指定されていないことを除いて。

そこから物事はうまくいかない。

于 2012-07-03T18:28:11.333 に答える
2

あなたの問題はそれです

template<enum E>

。という名前の前方宣言された列挙型を持つ名前のないパラメーターとして解釈されますE
意味的に同じ

template<int>

intに置き換えるだけenum Eです。

于 2012-07-03T18:29:41.803 に答える