引导构造函数(c++20)的越界定义



g++很乐意接受以下代码,而clang和msvc都能够匹配行外定义。

知道为什么吗?

template <bool B>
struct test 
{
test() requires (B);
test() requires(!B);
};

template <>
test<true>::test()
{}
template <>
test<false>::test()
{}
int main()
{
test<false> a;
test<true> b;
return 0;
}

演示

Clang:

错误:"test"的越界定义与"test<true>"中的任何声明都不匹配

Msvc:

错误C2244:"test<true>::test":无法将函数定义与现有声明匹配

您声明了受约束的构造函数,但定义了两个不受约束的专门化。这些永远不会匹配。

你的意思可能是:

template <bool B>
struct test
{
test() requires (B);
test() requires(!B);
};
template <bool B>
test<B>::test() requires (B)
{}
template <bool B>
test<B>::test() requires (!B)
{}

这在所有3个编译器中都能很好地编译。

至于为什么你的原始版本会编译,这是一个GCC错误96830。Clang是对的,代码格式不正确,因为行外定义与模板定义不匹配(还要注意,template<> ...完全专业化语法(。

参见【temp.class.general】/3(强调矿(:

当类模板的成员在类模板定义之外定义时,该成员定义被定义为模板定义,其模板头等效于类模板的

[temp.over.link]/6:

两个模板头等价的,如果它们的模版参数列表具有相同的长度,则相应的template参数等效,并且都用类型约束声明,如果其中一个模板参数type constraint声明,则等效,和如果模板头中的任何一个有requires子句,则它们都有requires从句,并且相应的约束表达式是等价的

另请参阅[temp.mem.func]/1,以获取声明受约束成员越界的示例:

template<typename T> struct S {
void f() requires C<T>;
void g() requires C<T>;
};
template<typename T>
void S<T>::f() requires C<T> { }      // OK
template<typename T>
void S<T>::g() { }                    // error: no matching function in S<T>

最新更新