clang vs gcc CRTP:constexpr 变量不能有非文字类型

Ant*_*ton 5 c++ gcc clang crtp constexpr

我这里有一个 CRTP 模板类:

template <typename S>
class Base
{
    public:
    constexpr static S NOT_SET{0};
};

struct Derived : public Base<Derived>
{
};
Run Code Online (Sandbox Code Playgroud)

Clang (5.0.0) 不接受这一点:

5 : <source>:5:24: error: constexpr variable cannot have non-literal type 'const Derived'
    constexpr static S NOT_SET{0};
                       ^
8 : <source>:8:25: note: in instantiation of template class 'Base<Derived>' requested here
struct Derived : public Base<Derived>
                        ^
5 : <source>:5:24: note: incomplete type 'const Derived' is not a literal type
    constexpr static S NOT_SET{0};
                       ^
8 : <source>:8:8: note: definition of 'Derived' is not complete until the closing '}'
struct Derived : public Base<Derived>
       ^
1 error generated.
Compiler exited with result code 1
Run Code Online (Sandbox Code Playgroud)

但 gcc(在 4.9.2 和 6.2 上测试)接受它很好。

如何在 clang 中做到这一点?

sky*_*ack 2

Derived当您尝试在类模板中使用它时,它不是完整的类型Base,因此您实际上不能那样使用它。这是因为类型必须完整才能声明该类型的变量。没有办法解决它。
\n总而言之,类型在结束时已完成}(以及与您的情况无关的其他异常,例如在其成员函数中)。
\n标准是这么说的(工作草案):

\n\n
\n

在\xc2\xa0类说明符的结束\xc2\xa0}\xc2\xa0处,类被视为完全定义的对象类型(或完整类型)。
\n 在类\xc2\xa0 成员规范中,该类在函数体、默认参数、noexcept 说明符和默认成员初始值设定项(包括嵌套类中的此类内容)内被视为完整。
\n 否则,它在其自己的类\xc2\xa0成员规范中被视为不完整。

\n
\n\n

因此 clang 是正确的,而错误的意思或多或少是相同的。

\n\n
\n\n

正如评论中提到的,存在一种解决方法。只要派生类型是(让我说)constexpr 可构造的,您就可以在基类中定义一个 constexpr 函数,该函数返回您未设置的版本(无论它意味着什么)。

\n