C++ 模板中的静态常量初始化顺序

C++ Static const initialization order in templates

本文关键字:常量 初始化 顺序 静态 C++      更新时间:2023-10-16

冒着被标记为重复的风险,我抓住机会。 请考虑以下事项:

给定以下静态常量数组 arrA 和 arrB,arrB 取决于 arrA。

#include <iostream>
#include <string>
#include <array>
template<int N>
class MyClass {
public:
static const std::array< int, N> arrA;
static const std::array< int, N> arrB;
};
template<int N>
std::array<int, N> const MyClass<N>::arrA = []() -> decltype(auto) {
std::array<int, N> arr;
for (int i = 0; i < N; i++) {
arr[i] = 1 + i;
}
return arr;
} ();
template<int N>
std::array<int, N> const MyClass<N>::arrB = []() -> decltype(auto) {
std::array<int, N> arr;
for (int i = 0; i < N; i++) {
arr[i] = arrA[i] + 1;
}
return arr;
} ();

int main()
{
constexpr int i = 3;
std::cout << std::to_string(MyClass<i>::arrB[0]) << std::endl;
}

如果我理解正确,这是标准中给出的静态常量成员无序初始化的情况:

1( 无序动态初始化,仅适用于(静态/线程本地(类模板静态数据成员和未显式专用化的变量模板(自 C++14 起(。对于所有其他动态初始化,此类静态变量的初始化是不确定的,除非程序在初始化变量之前启动线程,在这种情况下,其初始化是未排序的(自 C++17 起(。此类线程局部变量的初始化相对于所有其他动态初始化是无序的。

我能找到的最佳答案就在这里,但没有提到是否有一种已知的模式允许以有序的方式执行这种初始化。在保持static const的同时,这甚至可能吗?

理想情况下,我希望数组保持const,否则问题就微不足道了。

虽然这个例子可以用constexpr构建,但在实际情况下需要动态初始化(我使用<random>(。

编辑:我发现有趣的是,无论源代码中声明或定义的顺序如何,arrB都会在arrA之前初始化。

如果要保证初始化的顺序,则必须将两个数组包装在一个结构中,并使用结构的构造函数来初始化静态变量。这是我的意思的一个例子。

#include <iostream>
template <typename T>
struct A {
struct B {
B() : c(0), d(c + 1) {}
T c;
T d;
};
static B b;
static T& c() {
return b.c;
}
static T& d() {
return b.d;
}
};
template <typename T>
typename A<T>::B A<T>::b{};
int main() {
std::cout << A<int>::b.c << ", " << A<int>::b.d << std::endl;
std::cout << A<int>::c() << ", " << A<int>::d() << std::endl;
return 0;
}

如果你这样做,你可能想要提供访问器,如示例(c()d()( - 你也可以使用结构是私有的,并且对访问器的结果具有恒定性,所以,例如,你可以做

template <typename T>
struct A {
static const T& c() {
return b.c;
}
static T& d() {
return b.d;
}
private:   
struct B {
B() : c(0), d(c + 1) {}
T c;
T d;
};
static B b;
};