访问模板的静态constexpr成员作为常量表达式

时间:2018-05-14 20:44:26

标签: c++ templates constexpr

我试图将类模板的静态constexpr成员作为常量表达式访问,其中成员与所定义的类的类型相同。 MSVC和clang似乎都扼杀了这个简单的例子:

#include <iostream>

struct A
{
    static A const DEFAULT;

    constexpr A(int value = {}) : _value{ value } {}

    constexpr operator int() const { return _value; }

    int const _value;
};

constexpr A const A::DEFAULT{};

template<typename = void>
struct B_impl
{
    static B_impl const DEFAULT;

    constexpr B_impl(int value = {}) : _value{ value } {}

    constexpr operator int() const { return _value; }

    int const _value;
};

template<typename T>
constexpr B_impl<T> const B_impl<T>::DEFAULT{};

using B = B_impl<>;

template<int N>
constexpr int foo() { return N; }

int main(int, char**) noexcept
{
    std::cout << "A: " << foo<A::DEFAULT>() << "\n"; // IntelliSense hates this
    std::cout << "B: " << foo<B::DEFAULT>() << "\n"; // VC++ and clang die here:
    // MSVC error:  C2975  'N': invalid template argument for 'foo', expected compile-time constant expression
    // clang error:  note: candidate template ignored: invalid explicitly-specified argument for template parameter 'N'
    return 0;
}

gcc accepts both AB作为常量表达式。 MSVC和clang (demo)接受A作为常量表达式,并且对B没有问题,除非我尝试将其用作常量表达式,然后失败。

我试图在这里使用模板的全部原因是在不强制执行C ++ 17的情况下实现内联变量,因为这是在头文件中使用的。

在这个剥离的例子中,我可以使用静态constexpr函数来存储constexpr值,然后按值返回(因为constexpr函数中不允许使用静态constexpr变量,因此我无法通过引用返回) 。实际的代码有点复杂,我没有展示,因为它混淆了底层问题(gcc demo)。我实际上是在尝试存储一个值数组(正在定义的类型,因此内联constexpr定义是不可能的),对这些值的命名引用,所有这些都应该是静态的constexpr

同样,这可以在所有三个编译器上工作,如果我省略了模板,我不想这样做,因为这是在标题中我是尝试避免破坏ODR。

MSVC和clang是否因为拒绝这个模板化版本而受到抨击,或者gcc是否允许某些内容无法通过?

0 个答案:

没有答案