奇怪的重复模板模式 (CRTP),在 Clang 中使用静态 constexpr

Curiously recurring template pattern (CRTP) with static constexpr in Clang

本文关键字:Clang constexpr 静态 CRTP 模式      更新时间:2023-10-16

考虑我下面的简单例子:

#include <iostream>
template <typename T>
class Base
{
public:
    static constexpr int y = T::x;
};
class Derived : public Base<Derived>
{
public:
    static constexpr int x = 5;
};

int main()
{
    std::cout << Derived::y << std::endl;
}

在 g++ 中,这可以很好地编译并按预期打印5。 但是,在 Clang 中,它无法编译并显示错误 no member named 'x' in 'Derived' . 据我所知,这是正确的代码。 我正在做的事情有问题吗,如果没有,有没有办法在 Clang 中完成这项工作?

如注释中链接的那样,使用派生类的静态 constexpr 数据成员初始化基类的静态 constexpr 数据成员表明,此处的 clang 行为符合标准,最高可达 C++14。从 Clang 3.9 开始,您的代码使用 -std=c++1z 成功编译。一个简单的解决方法是使用 constexpr 函数而不是值:

#include <iostream>
template <typename T>
class Base
{
public:
    static constexpr int y() {return T::x();}
};
class Derived : public Base<Derived>
{
public:
    static constexpr int x() {return 5;}
};
int main()
{
    std::cout << Derived::y() << std::endl;
}

这可能不是任何人想要的答案,但我通过添加第三个类解决了这个问题:

#include <iostream>
template <typename T>
class Base
{
public:
    static constexpr int y = T::x;
};
class Data
{
public:
     static constexpr int x = 5;
};
class Derived : public Base<Data>, public Data {};
int main()
{
    std::cout << Derived::y << std::endl;
}

它可以按预期工作,但不幸的是,它并没有真正具有 CRTP 的好处!