约束成员模板的外定义规则是什么?

cig*_*ien 8 c++ templates language-lawyer

考虑以下代码

template <typename T>
struct S 
{
    template <typename = void>
    static constexpr bool B = true;

    template <std::enable_if_t<S<T>::template B<>, int> = 0>
    void f();
};

template <typename T>
template <std::enable_if_t<S<T>::template B<>, int>>
void S<T>::f() {}
Run Code Online (Sandbox Code Playgroud)

gcc 接受了这一点,但 clang 拒绝了它:

error: out-of-line definition of 'f' does not match any declaration in 'S<T>'
Run Code Online (Sandbox Code Playgroud)

之前已经过这个问题,但那里没有答案。


另一方面,如果B不是模板,我写了这段代码

template <typename T>
struct S 
{
    static constexpr bool B = true;

    template <std::enable_if_t<S<T>::B, int> = 0>
    void f();
};

template <typename T>
template <std::enable_if_t<S<T>::B, int>>
void S<T>::f() {}
Run Code Online (Sandbox Code Playgroud)

clang 接受了这一点,但 gcc 拒绝了以下代码:

error: no declaration matches 'void S<T>::f()'
Run Code Online (Sandbox Code Playgroud)

那么这些片段中的任何一个都有效吗?

Ber*_*nns 2

在定义过程中S<X>它是一个不完整类型。并且类成员访问运算符需要完整的类型。

但你可以用下面的代码解决这个问题:

#include <type_traits>

template <typename T>
struct S {

    template <typename = void>
    static constexpr bool B = true;

    template <
        typename TX = T,
        std::enable_if_t<S<TX>::template B<>, int> = 0>
    void f();
};

template <typename T>
template <typename TX, std::enable_if_t<S<TX>::template B<>, int>>
void S<T>::f() {}

//-----------

template <typename T>
struct S2 {

    static constexpr bool B = true;

    template <
        typename TX = T,
        std::enable_if_t<S2<TX>::B, int> = 0>
    void f();
};

template <typename T>
template <typename TX, std::enable_if_t<S2<TX>::B, int>>
void S2<T>::f() {}
Run Code Online (Sandbox Code Playgroud)

  • 您能否指出标准中的何处将其定义为“格式错误的程序,无需诊断”?(我认为标准中引用的次数不到十几次)。我问是因为这是一个[标签:语言律师]问题。 (2认同)