初始化类模板的静态 constexpr 成员变量

时间:2021-05-18 07:11:25

标签: c++ templates c++17 c++14 constexpr

情况如下:带有模板参数 Foo 的类 int N 具有静态成员变量 float valval 的值对应于 N 并且永远不会改变,所以我希望它是 constexpr

我知道初始化静态 constexpr 成员变量的常用方法是:

// ok, but not what I want
template <int N>
struct Foo {
    static constexpr float val { 0.0f };
};
template <int N>
constexpr float Foo<N>::val;

但是因为 val 是在类作用域内部初始化的,所以我不能为不同的 val 指定不同的 N

如果 val 不是 constexpr 而是 const,这是有效的:

// ok, but not what I want
template <int N>
struct Foo {
    static const float val;
};
template <>
const float Foo<0>::val = 3.14f;
template <>
const float Foo<1>::val = 0.1f;

但是我不能使用 constexpr float val = Foo<0>::val;,因为 Foo<0>::val 不是一个常量表达式。

所以,我想要实现的目标如下:

// the thing I want, but error
template <int N>
struct Foo {
    static constexpr float val;
};
template <>
constexpr float Foo<0>::val = 3.14f;
template <>
constexpr float Foo<1>::val = 0.1f;

但编译器抱怨:

<块引用>

错误:constexpr 静态数据成员 'val' 的声明需要初始化程序

如果我为 val (static constexpr float val { 0.0f };) 添加一个初始化程序,编译器会说:

<块引用>

错误:重复初始化 'Foo<0>::val'
错误:'Foo<1>::val'

的重复初始化

多么讽刺 :D

我知道的一种解决方法是使用 variable template (C++14):

// ok
struct Foo {
    template <int N>
    static constexpr float val { 0.0f };
};
template <>
constexpr float Foo::val<0> = 3.14f;
template <>
constexpr float Foo::val<1> = 0.1f;

这目前按预期工作。但如果 Foo 中的其他成员(变量或函数)仍然需要模板参数(即 Foo 需要是类模板),则此方案不适用。

对此有什么想法吗?首选使用低于 C++20 的 C++ 标准的解决方案(C++20 对我的项目来说太新了)。

1 个答案:

答案 0 :(得分:5)

您可以将类模板专门化为

template <int N>
struct Foo {
    static constexpr float val { 0.0f };
};
template <>
struct Foo<0> {
    static constexpr float val { 3.14f };
};
template <>
struct Foo<1> {
    static constexpr float val { 0.1f };
};

或者为初始化做一个函数助手。

template <int N>
struct Foo {    
    static constexpr float get_val() {
        if constexpr (N == 0) return 3.14f;
        else if constexpr (N == 1) return 0.1f;
        else return 0.0f;
    }
    static constexpr float val { get_val() };
};