静态数据成员:它"const declaration / constexpr definition"起作用?

Static data member: "const declaration / constexpr definition" does it work?

本文关键字:constexpr definition 起作用 const 数据成员 静态 declaration      更新时间:2023-10-16

以下一段代码试图提供一个 constexpr 属于类型 X 本身的 X 类型的静态数据成员。 在标准库(C++20(中,似乎有这样的例子 (至少(具有类"std::strong_ordering"及其少数静态 ConstexPR成员命名为"相等","更少","更大"和"等效"。 我想知道是否可以(以及如何(在没有编译器魔法的情况下实现这一目标。

直接声明(包括定义(确实如此 似乎不适用于任何编译器,也不是有效的C++。 话虽如此,后来又声明为"const" (在类之外(根据"constexpr"的定义似乎 与 GCC 一起工作,至少在某些情况下与 Clang 一起工作。

我的问题如下:

  1. 技巧是否由"常量声明"后跟 "constexpr 定义"形成实际提供的有效C++代码 在 X 类本身内,X 类型的有效静态 constexpr 数据成员?
  2. 非模板版本(Foo类型(使用GCC和Clang编译 而模板版本(类型Bar<0>(仅使用 GCC 编译。 是否有任何规则可以使非模板版本 有效的C++代码和模板一个无效的C++代码?
  3. Clang生成的错误可以被视为编译器错误吗?

源代码 (C++17(:

// With this non template struct,
// It compiles successfully with GCC and Clang.
struct Foo
{
// A data member.
int val;
// A static data member.
// It is declared here as 'const'
// and defined below as 'constexpr'.
static Foo const instance;
// A constexpr constructor.
constexpr Foo(int value) noexcept : val{ value } {}
};
// With this non template struct,
// It compiles successfully with GCC
// but it generates an error with Clang.
template<int N>
struct Bar
{
// A data member.
int val;
// A static data member.
// It is declared here as 'const'
// and defined below as 'constexpr'.
static Bar const instance;
// A constexpr constructor.
constexpr Bar(int value) noexcept : val{ value } {}
};
// Definition of the static
// data member of the struct Foo.
// Note that it is defined here as 'constexpr'
// while it was declared above only as 'const'.
constexpr Foo const Foo::instance{32};
// Definition of the static data
// member of the template struct Foo.
// Note that it is defined here as 'constexpr'
// while it was declared above only as 'const'.
template<int N>
constexpr Bar<N> const Bar<N>::instance{32};
// The main function.
int main()
{
// Init a constexpr const reference to
// the static data member object of type Foo.
constexpr Foo const& foo{ Foo::instance };
// Init a constexpr const reference to
// the static data member object of type Bar<0>.
constexpr Bar<0> const& bar{ Bar<0>::instance };
// This compile time check
// works fine with GCC and Clang.
static_assert(foo.val == 32);
// This compile time check works fine with GCC
// but generates a compilation error with Clang.
static_assert(bar.val == 32);
// Return zero.
return 0;
};

以前的堆栈溢出相关问题:

我引用了两个StackOverflow问题,它们是 相关但(在我看来(没有清楚地回答我的问题。

  1. 这个试图实现与我相同的目标,但似乎没有 提到"常量声明/constexpr 定义"技巧。一个类不能有自己的静态 constexpr 成员实例吗?

  2. 这个提到了"const 声明/constexpr 定义"技巧,但是 没有清楚地回答它是否有效的问题C++代码。静态常量声明,变量的constexpr定义,有效的c ++?

关于std::strong_ordering的例子:C++标准本身声明这些静态数据成员是用const声明的,并在类外部用inline constexpr定义,所以这应该被认为是这种技术实际上在标准C++中工作的有力证据。例如,请参阅此处。

我在标准中找不到任何理由证明 Clang 只有在模板化时才拒绝这一点。似乎已经针对Clang提交了识别特定问题的错误,尽管维护者似乎尚未确认。