【问题标题】:CRTP compiling errorCRTP 编译错误
【发布时间】:2016-03-02 17:18:39
【问题描述】:

以下内容将使用 GCC 5.2 编译,但不能使用 Visual Studio 2015。

template <typename Derived>
struct CRTP {
    static constexpr int num = Derived::value + 1;
};

struct A : CRTP<A> {
    static constexpr int value = 5;
};

它抱怨A 没有名为value 的成员。 如何修复代码以便在两个编译器上编译?还是完全违法?

【问题讨论】:

  • 在clang上也编译失败。
  • 是不是语法不合法,而 GCC 只是侥幸脱身?
  • 我不确定,但它看起来应该是非法的,否则你可以有num = Derived::valuevalue = CRTP&lt;V&gt;::num
  • 但是在 GCC 上它可以编译,并且在运行我的程序时,所有输出都符合预期,即没有未定义的行为。
  • Derived=A 不完整,所以我怀疑这是有效的

标签: c++ templates c++11 constexpr crtp


【解决方案1】:

尝试将其设为 constexpr 函数。您现在的设置方式会尝试访问不完整的类型。
由于模板化的成员函数只会在第一次使用时被初始化,因此 A 类型将在此时完全定义。

#include <iostream>

template <typename Derived>
struct CRTP {
    static constexpr int num() { return  Derived::value + 1; }
};

struct A : CRTP<A> {
    static constexpr int value = 5;
};

int main()
{
    std::cout << A::num();
    return 0;
}

现场观看here

【讨论】:

    【解决方案2】:

    问题出在这里:

    template <typename Derived>
    struct CRTP {
        static constexpr int num = Derived::value + 1;
                                   ↑↑↑↑↑↑↑↑↑
    };
    

    CRTP&lt;A&gt; 实例化时,A 还不是一个完整的类,因此您实际上无法访问它的静态成员。

    一种解决方法是将num 作为单独的模板参数传入:

    template <typename Derived, int N>
    struct CRTP {
        static constexpr int num = N;
    };
    
    struct A : CRTP<A, 5> {
    
    };
    

    【讨论】:

    • 为什么CRTP&lt;Derived&gt;::num的初始化器需要在CRTP&lt;Derived&gt;被实例化的时候被实例化?你能提供标准的参考吗?
    • 我发现的是[temp.inst] p9:“类模板的隐式实例化不会导致该类的任何静态数据成员被隐式实例化”。
    • @HighCommander4 这与成员的定义有关 - 声明仍然必须被解析和有效,它不在 OP 的示例中,因为 Derived 尚不完整。跨度>
    猜你喜欢
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-19
    • 1970-01-01
    相关资源
    最近更新 更多