我有课:
#include <array>
template<class T, std::size_t N>
requires std::is_arithmetic_v<T> && (N >= 1)
class Vector
{
static constexpr std::size_t Dimension = N;
std::array<T, Dimension> Elements;
public:
constexpr Vector() noexcept : Elements{} {}
constexpr ~Vector() = default;
static constexpr Vector ZeroVector{};
};
int main()
{
Vector<float, 7> boo = Vector<float, 7>::ZeroVector;
}
上面的代码无法在具有 C++23 编译器标志的 MSVC 和 Clang (trunk) 的编译器资源管理器上编译,但它可以在具有 C++23 编译器标志的 GCC (trunk) 上编译。
Clang 给出以下错误:
<source>:13:29: error: constexpr variable cannot have non-literal type 'const Vector<float, 7>'
13 | static constexpr Vector ZeroVector{};
| ^
<source>:18:28: note: in instantiation of template class 'Vector<float, 7>' requested here
18 | Vector<float, 7> boo = Vector<float, 7>::ZeroVector;
| ^
<source>:13:29: note: incomplete type 'const Vector<float, 7>' is not a literal type
13 | static constexpr Vector ZeroVector{};
| ^
<source>:5:7: note: definition of 'Vector<float, 7>' is not complete until the closing '}'
5 | class Vector
| ^
1 error generated.
Compiler returned: 1
MSVC 给出以下错误:
<source>(13): error C2027: use of undefined type 'Vector<float,7>'
<source>(5): note: see declaration of 'Vector<float,7>'
<source>(13): note: the template instantiation context (the oldest one first) is
<source>(18): note: see reference to class template instantiation 'Vector<float,7>' being compiled
Compiler returned: 2
当我将
constexpr
更改为 const constinit
时,当定义移到类之外时,这会在所有三个主要编译器上进行编译,如下所示:ZeroVector
那么为什么
template<class T, size_t N> requires std::is_arithmetic_v<T> && (N >= 1)
const constinit Vector<T, N> Vector<T, N>::ZeroVector{};
只能在 GCC 上编译,而
constexpr
可以在所有三个主要编译器上编译?来自 dcl.constexpr:
对象声明中使用的 constexpr 说明符将对象声明为 const。 这样的对象应具有文字类型并应进行初始化。
在任何 constexpr 变量声明中,初始化的完整表达式应为常量表达式 ([expr.const])。 作为对象的 constexpr 变量以及绑定了 constexpr 引用的任何临时变量,应不断销毁。(强调我的)
并且
const constinit
满足成为
文字类型的条件。
因此 gcc 没有给出相同的诊断是正确的。