enum 型とテンプレート特殊化

追記: テンプレートの特殊化と同時にインスタンス化されていたというだけでした。仕様のどこに書いてあるのかは調査中以下のように template specialization というのはインスタンス化されたもの、明示的に特殊化されたもの両方を内包する概念のようでした。

14.7.4: An instantiated template specialization can be either implicitly instantiated (14.7.1) for a given argument list or be explicitly instantiated (14.7.2). A specialization is a class, function, or class member that is either instantiated or explicitly specialized (14.7.3).

ISO/IEC 14882:1998 (たぶん本物) から引用。

3.9.2.1: enumerations, which comprise a set of named constant values. Each distinct enumeration constitutes a different enumerated type

と、あるんですが...

enum X { A };

template<typename T_>
struct foo {
    struct bar;
    enum { _ = sizeof(bar) };
};

template<>
struct foo<enum X> {};

#ifdef OUCH
/* 以下の specialization が、上の enum X より優先される? */
template<>
struct foo<int> {
    struct bar;
    enum { _ = sizeof(bar) };
};
#endif

foo<enum X> _1;

うーん、こういうもんだっけ?

ちなみに、

enum X { A };
enum Y { B };

template<typename T_>
struct foo {
    struct bar;
    enum { _ = sizeof(bar) };
};

template<>
struct foo<enum X> {};

foo<enum X> _1;

#ifdef OUCH
foo<enum Y> _2;
#endif

で、

#include <typeinfo>
#include <iostream>

enum X { A };

template<typename T_>
inline bool is_int(T_ const& val)
{
    return typeid(val) == typeid(int);
}

int main()
{
    std::cout << is_int(1) << std::endl; // 1
    std::cout << is_int(A) << std::endl; // 0
    return 0;
}

で、

#include <iostream>

enum X { A };

template<typename T_>
struct foo {
    static const int value = 0;
};

template<>
struct foo<enum X> {
    static const int value = 1;
};

template<>
struct foo<int> {
    static const int value = 2;
};

int main()
{
    std::cout << foo<enum X>::value << std::endl; // 1
}

ところで、

// 3.9.1.1: char, signed char, and unsigned char are three distinct types.

template<typename T_>
struct foo {
    struct bar;
    enum { _ = sizeof(bar) };
};

template<>
struct foo<signed char> {};

foo<signed char> _1;

#ifdef OUCH
// signed int / int と違って、
// char は signed char とは違う型 (distinct type)
foo<char> _2;
#endif

これは仕様通り。

// 3.9.1.5: Type wchar_t shall have the same size, signedness, and alignment requirements (3.11) as one of the other integral types, called its underlying type. 

template<typename T_>
struct foo {
    struct bar;
    enum { _ = sizeof(bar) };
};

template<>
struct foo<signed wchar_t> {};

foo<signed wchar_t> _1;

foo<wchar_t> _2; // OK

こちらも仕様通りなんだけど、ちょっと一貫性がないですね。