【问题标题】:Compiler error when using CRTP with static_assert将 CRTP 与 static_assert 一起使用时出现编译器错误
【发布时间】:2016-04-26 15:42:45
【问题描述】:

考虑以下代码:

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;

这在 gcc 上编译得很好,但如果我取消注释 static_assert 行,它会抱怨

error: incomplete type 'Derived' used in nested name specifier
static constexpr int x_base = Derived::x_derived;

我尝试了从 4.9 到 5.3 的不同版本的 gcc,我得到了同样的错误(你可以在 godbolt here 上试试)。即使没有static_assert,clang 也拒绝编译它,并抱怨

error: no member named 'x_derived' in 'Derived'
static constexpr int x_base = Derived::x_derived;

哪个编译器是正确的(如果有的话)? 有没有修复代码的好方法?

【问题讨论】:

    标签: c++ gcc clang crtp static-assert


    【解决方案1】:

    访问嵌套名称需要类是完整的,但 Derived 在这里还不完整:

    template<typename Derived>
    struct Base {
        static constexpr int x_base = Derived::x_derived;
                                      ^^^^^^^^^
    };
    

    所以代码格式不正确。

    有一些解决方法。首先,您可以单独将值作为模板参数传入:

    template <typename Derived, int x_derived>
    struct Base {
        static constexpr int x_base = x_derived;
    };
    
    struct Derived : public Base<Derived, 5> { };
    

    其次,如果可能(例如,您不需要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;
    };
    

    【讨论】:

    • 感谢巴里的精彩回答。所以,如果我理解正确的话,gcc 接受没有 static_assert 的代码这一事实是编译器错误,而 clang 拒绝它是正确的?
    • @toth gcc 不会拒绝它,直到您在任何地方实际使用它 - 所以在这方面它只是更友好一点。但是仅仅声明一个你从不使用的变量并没有真正的意义——所以它会在重要的地方正确地拒绝它。
    • 但 gcc 确实允许我使用它,只要它不在 static_assert 中。例如,godbolt.org/g/rfbH5c(而 clang 继续拒绝代码)。所以其中一个编译器一定是错的,知道哪个吗?
    • @toth gcc 应该拒绝它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-03
    • 1970-01-01
    • 1970-01-01
    • 2011-01-11
    • 1970-01-01
    • 2013-10-08
    相关资源
    最近更新 更多