引导构造函数的外行定义(c++20)

red*_*der 6 c++ constructor require 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;
}
Run Code Online (Sandbox Code Playgroud)

演示

铛:

错误:超出行的“定义test”不匹配中的任何声明“ test<true>

msvc:

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

rus*_*tyx 6

您正在声明受约束的构造函数,但定义了两个不受约束的特化。那些永远不会匹配。

你的意思可能是:

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)
{}
Run Code Online (Sandbox Code Playgroud)

这在所有 3 个编译器中都可以正常编译。

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

[temp.class.general]/3(强调我的):

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

[temp.over.link]/6 :

如果它们的模板参数列表具有相同的长度,则两个模板头等效的,相应的模板参数是等效的,并且都使用类型约束声明,如果模板参数声明为类型约束,并且如果要么模板头有一个requires-clause,它们都有requires-clauses,对应的constraint-expressions 是等价的

另请参阅[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>
Run Code Online (Sandbox Code Playgroud)