在模板 class 内定义的枚举上嵌套 class 的部分特化
Partial specialization of nested class on enum defined inside a template class
请看下面代码:
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_directory\test.cpp(15): error C2039: 'f': is not a member of 'X<int>::Y<int,X<int>::E::e0>'
1> some_directory\test.cpp(15): note: see declaration of 'X<int>::Y<int,X<int>::E::e0>'
1> some_directory\test.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
是在模板 class 中定义的。事实上,如果我将 enum class E
移到 X
之外,错误就会消失(在旧版本和最近的 15.7.5 中)。
这种情况真的是依赖非类型模板参数的部分特化吗?
GCC 和 Clang 接受它是正确的。这都是根据[temp.class.spec]/5,其中还有一个支持示例:
A class template partial specialization may be declared in any scope in which the corresponding primary template may be defined ([namespace.memdef], [class.mem], [temp.mem]). [ Example:
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
— end example ]
使用 MSVC 的解决方法可能是尝试在命名空间范围内专门化成员模板。
至于你的编辑,我想说 MSVC 仍然是错误的。相关标准在 [temp.class.spec]/8:
Within the argument list of a class template partial specialization, the following restrictions apply:
The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the specialization. [ Example:
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
— end example ]
将其应用于 struct Y<U, E::e0>
中的示例:枚举的类型是否取决于 Y
的另一个模板参数?答案是不。它当然取决于 X<T>
,但那是 另一个 模板专业化。与我们在编写定义时部分专门化的模板不同。