谁是对的?
GCC 接受所有情况是正确的,而 Clang 和 MSVC 拒绝它们是错误的;部分特化的类外定义应通过等效的 template-head:s 与其声明相匹配,其中包括约束(如果有)。
Foo的主模板的template-head不等价于它的两个约束偏特化的template-head,定义因此,主模板不应与其约束特化的成员函数的类外定义冲突。
我对部分模板专业化有基本的误解吗?
不,从这个问题的外观来看不是。
如何让这个在 MSVC 上运行?
由于 MSVC 和 Clang 一样,似乎(目前)在区分 template-head:s 的类外定义时存在问题(特别是在通过约束部分专门化类模板时显示) ,您将需要在使用 MSVC 编译时避免后者(目前)。由于可能没有相关的 MSVC 错误报告,您可能需要考虑提交一份。
详情
根据[temp.spec.partial.general]/4,部分专业化可能确实受到限制:
可能会限制部分特化 ([temp.constr])。 [例子
2:
template<typename T> concept C = true;
template<typename T> struct X { };
template<typename T> struct X<T*> { }; // #1
template<C T> struct X<T> { }; // #2
[...] — 结束示例]
只要the declaration of the primary template precedes it。
我们可能会将您的示例最小化为以下内容:
template <typename>
concept C = true;
template <typename T>
struct S;
template <C T>
struct S<T> { void f(); };
template <C T>
void S<T>::f() {}
哪个 GCC 接受但 Clang 拒绝
prog.cc:12:12: 错误:来自类 S<T> 的 f 的外线定义没有定义
void S<T>::f() {}
~~~~~~^
意思是 Clang 解释类外定义
template <C T>
void S<T>::f() {}
因为有一个与主模板等效的template-head,这是错误的,因为 template-head 包括 template-parameter:s,而 type-parameter:s 又包括 type-parameter:s type-constraints:s,如果有的话。
template-head:s 的等价性由[temp.over.link]/6 管理,其中包括约束[emphasis mine]:
两个模板头是等价的如果他们的模板参数列表有相同的长度,对应template-parameters 是等效的,并且 都使用 type-constraints 声明,如果任一模板参数使用 type-constraint 声明,则它们是等效的em>,如果任一 template-head 有
requires-clause,它们都有 requires-clauses 和
对应的约束表达式是等价的。
最后,尽管是非规范性的,[temp.mem] 的 示例 2 和
[...] 成员模板可以在其类内部或外部定义
定义或类模板定义。类的成员模板
在其类模板定义之外定义的模板
应使用与类模板等效的 template-head 指定,后跟与类模板等效的 template-head
成员模板([temp.over.link])。 [...]
[示例2:
template<typename T> concept C1 = true;
template<typename T> concept C2 = sizeof(T) <= 4;
template<C1 T> struct S {
template<C2 U> void f(U);
template<C2 U> void g(U);
};
template<C1 T> template<C2 U>
void S<T>::f(U) { } // OK
template<C1 T> template<typename U>
void S<T>::g(U) { } // error: no matching function in S<T>
——结束示例]
和 [temp.class.general] 的示例 2:
[示例2:
// ...
template<typename T> concept C = true;
template<typename T> concept D = true;
template<C T> struct S {
void f();
void g();
void h();
template<D U> struct Inner;
};
template<C A> void S<A>::f() { } // OK: template-heads match
template<typename T> void S<T>::g() { } // error: no matching declaration for S<T>
template<typename T> requires C<T> // ill-formed, no diagnostic required: template-heads are
void S<T>::h() { } // functionally equivalent but not equivalent
template<C X> template<D Y>
struct S<X>::Inner { }; // OK
——结束示例]
显示受约束类模板特化的成员函数的类外定义示例。
这尤其是 Clang 错误:
我不知道是否有类似的 MSVC 错误报告。