模板化 constexpr 变量

Templated constexpr variable

我想确认此代码是否合法(或不合法?)C++17。

#include <iostream>

template<int N> inline constexpr float MyConst;

template<> inline constexpr float MyConst<1> = 1.1f;
template<> inline constexpr float MyConst<2> = 2.2f;

int main ()
{
    std::cout << MyConst<1> << '\n';

    return 0;
}

如果由 g++MSVC,

编译,我不会收到错误(并得到正确的输出)

但是Intelclang报错:

test.cpp(3): error: missing initializer for constexpr variable
  template<int N> inline constexpr float MyConst;
                         ^

使用 -std=c++17 编译(/std:c++17 for MSVC)。

在 Godbolt 和我的本地机器上尝试了最新的编译器。

问题是 constexpr 需要初始化。

C++14 标准,来自第 7.5.1 节第 9 段,

A constexpr specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized.

然后:

#include <iostream>

template<int N> inline constexpr float MyConst = 0.0f;

template<> inline constexpr float MyConst<1> = 1.1f;
template<> inline constexpr float MyConst<2> = 2.2f;

int main ()
{
    std::cout << MyConst<1> << '\n';

    return 0;
}

对 g++ 和 clang 都很好。

一个constexpr变量必须立即初始化。因此 MyConst 的模板需要一个 initialiser/definition。 GCC 不要求在第一次出现时定义,这与规范背道而驰。如果您使用变量的非专业形式,例如MyConst<3> you will get a similar error from GCC:

<source>: In instantiation of 'constexpr const float MyConst<3>':
<source>:10:18:   required from here
<source>:3:40: error: uninitialized 'const MyConst<3>' [-fpermissive]
    3 | template<int N> inline constexpr float MyConst;
      |                                        ^~~~~~~
ASM generation compiler returned: 1
<source>: In instantiation of 'constexpr const float MyConst<3>':
<source>:10:18:   required from here
<source>:3:40: error: uninitialized 'const MyConst<3>' [-fpermissive]
    3 | template<int N> inline constexpr float MyConst;
      |                            

这可以通过为 MyConst 提供初始定义来解决,例如

// Use a "sensible default"
template<int N> inline constexpr float MyConst(0.0f);

// Provide a more general definition
template<int N> inline constexpr float MyConst = N*1.1f;

标准的相关部分,参见dcl.constexpr paragraph 1

The constexpr specifier shall be applied only to the definition of a variable or variable template or the declaration of a function or function template. The consteval specifier shall be applied only to the declaration of a function or function template. A function or static data member declared with the constexpr or consteval specifier is implicitly an inline function or variable. If any declaration of a function or function template has a constexpr or consteval specifier, then all its declarations shall contain the same specifier.

这是DR 1712

一方面,constexpr 变量必须初始化,另一方面,template 在实例化之前不是“事物”,因此在实例化之前不一定需要初始值那么

遗憾的是,该标准目前并未免除 constexpr 变量模板具有初始值的要求。所以从技术上讲,代码格式不正确。

对应的GCC问题是#68012,询问是否需要诊断。