请参阅以下代码:
template <class T>
struct X {
enum class E { e0 };
template <class U, E e>
struct Y {};
template <class U>
struct Y<U, E::e0> {
static int f() { return 0; }
};
};
int main() {
X<int>::Y<int, X<int>::E::e0>::f();
}
VC++15.7.5生成错误消息:
1> test.cpp
1> some_directorytest.cpp(15): error C2039: 'f': is not a member of 'X<int>::Y<int,X<int>::E::e0>'
1> some_directorytest.cpp(15): note: see declaration of 'X<int>::Y<int,X<int>::E::e0>'
1> some_directorytest.cpp(15): error C3861: 'f': identifier not found
然而,GCC&Clang似乎接受了这个代码。
哪一个是正确的?
编辑
在较旧版本的VC++上生成以下错误消息:
source_file.cpp(9): error C2754: 'X<T>::Y<U,>': a partial specialization cannot have a dependent non-type template parameter
source_file.cpp(12): note: see reference to class template instantiation 'X<T>' being compiled
source_file.cpp(16): error C2039: 'f': is not a member of 'X<int>::Y<int,X<int>::E::e0>'
source_file.cpp(16): error C3861: 'f': identifier not found
所以我认为VC++拒绝编译的原因是enum class E
是在模板类中定义的。事实上,如果我将enum class E
移到X
之外,错误就会消失(在旧版本和最近的15.7.5中都是如此(。
这种情况真的是对依赖的非类型模板参数进行部分专门化的情况吗?
GCC和Clang接受它是正确的。这都是根据[temp.class.spec]/5,它还有一个支持示例:
类模板部分专用化可以在任何范围内声明其中可以定义相应的主模板([名称空间.内存定义],[类别.内存],[临时.内存]([示例:
template<class T> struct A { struct C { template<class T2> struct B { }; template<class T2> struct B<T2**> { }; // partial specialization #1 }; }; // partial specialization of A<T>::C::B<T2> template<class T> template<class T2> struct A<T>::C::B<T2*> { }; // #2 A<short>::C::B<int*> absip; // uses partial specialization #2
—结束示例]
MSVC的一个变通方法可能是尝试在命名空间范围内专门化成员模板。
至于你的编辑,我认为MSVC仍然是错误的。相关标准为[温度等级规范]/8:
在类模板部分专业化的参数列表中,以下限制适用:
与专用非类型参数相对应的模板参数的类型不应依赖于专业化[示例:
template <class T, T t> struct C {}; template <class T> struct C<T, 1>; // error template< int X, int (*array_ptr)[X] > class A {}; int array[5]; template< int X > class A<X,&array> { }; // error
—结束示例]
将其应用于struct Y<U, E::e0>
中的示例:枚举的类型是否取决于Y
的另一个模板参数?答案是否定的。这当然取决于X<T>
,但这是另一个模板专用化。与我们在编写定义时部分专业化的模板不同。