将类定义传递给基类时是否完成了类定义?

将类定义传递给基类时是否完成了类定义?

问题描述:

我想写一个CRTP来包含派生类型的static constexpr,因为这对于一个类是不可能的。此代码在GCC中编译良好,但是clang抱怨Derived是不完整的类型。哪一个是对的?将类定义传递给基类时是否完成了类定义?

template<class T> 
class Base { 
public: 
    static constexpr T a = T(1), b = T(20); 
}; 

class Derived : public Base<Derived> { 
public: 
    int x; 
    constexpr Derived(int x) : x(x) {} 
}; 
+1

在Derived的构造函数中注意局部变量x和成员具有相同的名称 – Brahim

+0

我只想指出,将基类中的派生对象保留为静态并不是最好的想法.. –

+0

执行此操作的唯一原因这种方式是因为我不能把'Derived'类型的'static constexpr'放入'Derived'中。我希望能够这样做:'Derived :: a',而不是像'Derived :: constants :: a'这样的东西。 – user975989

Derived是在该Base<Derived>被实例化([class.mem]/2)的点,这右在定义时发生不完全的。你使用了constexpr,它需要根据[class.static.data]/3初始化器,并且当Base<Derived>被实例化时,其静态数据成员([temp.inst]/3)的声明也是如此,其中包括初始化器。但是,初始化器试图创建一个不完整类型的对象,这是不合格的。

你可以声明你的成员作为const代替:

template<class T> 
class Base { 
public: 
    static const T a; 
}; 
template <typename T> 
constexpr T Base<T>::a = T(1); 

因为初始化现在是定义,这个初始化的实例可以推迟到例如Derived已完成。 Demo与Clang。

请注意,Clang尚未将a视为constexpr,因为它未能急于实例化其定义。查看错误#24541

+0

但是你不能这样做'static_assert(Derived :: ax == 1,“”)'',这种类型会破坏'constexpr'的目的。 – user975989

+0

@ user975989这似乎是一个叮当虫。 – Columbo

+0

@ user975989找到DR并将其添加到答案中。 (有趣的是,使用的例子是非常重要的!) – Columbo