tot*_*oth 7 c++ gcc clang static-assert crtp
请考虑以下代码:
template<typename Derived>
struct Base {
static constexpr int x_base = Derived::x_derived;
//static_assert(x_base > 1, "Oops");
};
struct Derived : public Base<Derived> {
static constexpr int x_derived = 5 ;
};
Base<Derived> obj;
Run Code Online (Sandbox Code Playgroud)
这在gcc上编译很好,但如果我取消注释该static_assert行,它会抱怨
error: incomplete type 'Derived' used in nested name specifier
static constexpr int x_base = Derived::x_derived;
Run Code Online (Sandbox Code Playgroud)
我从4.9到5.3的不同版本的gcc试了一下,我也得到了同样的错误(你可以尝试在godbolt 这里).即使没有static_assert,clang也拒绝编译它,并抱怨
error: no member named 'x_derived' in 'Derived'
static constexpr int x_base = Derived::x_derived;
Run Code Online (Sandbox Code Playgroud)
哪个编译器是正确的(如果有的话)?有没有一种很好的方法来修复代码?
Bar*_*rry 10
访问嵌套名称要求类完整,但Derived尚未完成:
template<typename Derived>
struct Base {
static constexpr int x_base = Derived::x_derived;
^^^^^^^^^
};
Run Code Online (Sandbox Code Playgroud)
所以代码是不正确的.
有一些解决方法.首先,您可以单独传递值作为模板参数:
template <typename Derived, int x_derived>
struct Base {
static constexpr int x_base = x_derived;
};
struct Derived : public Base<Derived, 5> { };
Run Code Online (Sandbox Code Playgroud)
其次,如果可能(例如,您不需要x_derived声明任何成员),您可以将值移动到函数中以延迟其实例化:
template<typename Derived>
struct Base {
static constexpr int x_base() {
static_assert(Derived::x_derived > 1, "Oops");
return Derived::x_derived;
}
};
struct Derived : public Base<Derived> {
static constexpr int x_derived = 5;
};
Run Code Online (Sandbox Code Playgroud)