在编译时通过算法初始化一个 std::array
Initialize an std::array algorithmically at compile time
考虑:
static constexpr unsigned num_points{ 7810 };
std::array< double, num_points > axis;
for (int i = 0; i < num_points; ++i)
{
axis[i] = 180 + 0.1 * i;
}
axis
是 class 范围内的常量。我想避免像任何其他全局变量一样初始化它。可以在编译时完成吗?
这是最终的 class 完整内容:
// https://www.nist.gov/pml/atomic-spectroscopy-compendium-basic-ideas-notation-data-and-formulas/atomic-spectroscopy
// https://www.nist.gov/pml/atomic-spectra-database
struct Spectrum
{
static constexpr unsigned _num_points{ 7810 };
using Axis = std::array< double, _num_points >;
static constexpr Axis _x{ [] () // wavelength, nm
{
Axis a {};
for( unsigned i = 0; i < _num_points; ++i )
{
a[ i ] = 180 + 0.1 * i;
}
return a;
} () };
Axis _y {}; // radiance, W·sr−1·m−2
};
代码和变量的混用很难看,但至少公式就在reader眼前。任何其他解决方案都涉及大量输入以获得 in-class 定义的常量和类型。
或者如果我改变炉膛,我可以在运行时简单地 return lambda。
这里是完整的可编译代码:
#include <array>
template<int num_points>
static constexpr std::array<double, num_points> init_axis() {
std::array<double, num_points> a{};
for(int i = 0; i < num_points; ++i)
{
a[i] = 180 + 0.1 * i;
}
return a;
};
struct Z {
static constexpr int num_points = 10;
static constexpr auto axis = init_axis<num_points>();
};
为了完整起见,这里有一个不需要定义函数而是使用 lambda 的版本。 C++17 引入了在常量表达式中使用 lambda 的能力,因此您可以声明数组 constexpr
并使用 lambda 对其进行初始化:
static constexpr auto axis = [] {
std::array<double, num_points> a{};
for (int i = 0; i < num_points; ++i) {
a[i] = 180 + 0.1 * i;
}
return a;
}();
(注意最后一行的 ()
,它会立即调用 lambda。)
如果您不喜欢 axis
声明中的 auto
因为它使实际类型更难阅读,但又不想在 lambda 中重复该类型,你可以改为:
static constexpr std::array<double, num_points> axis = [] {
auto a = decltype(axis){};
for (int i = 0; i < num_points; ++i) {
a[i] = 180 + 0.1 * i;
}
return a;
}();
还有 std::index_sequence
技巧 (Wandbox example):
template <unsigned... i>
static constexpr auto init_axis(std::integer_sequence<unsigned, i...>) {
return std::array{(180 + 0.1 * i)...};
};
static constexpr auto axis = init_axis(std::make_integer_sequence<unsigned, num_points>{});
考虑:
static constexpr unsigned num_points{ 7810 };
std::array< double, num_points > axis;
for (int i = 0; i < num_points; ++i)
{
axis[i] = 180 + 0.1 * i;
}
axis
是 class 范围内的常量。我想避免像任何其他全局变量一样初始化它。可以在编译时完成吗?
这是最终的 class 完整内容:
// https://www.nist.gov/pml/atomic-spectroscopy-compendium-basic-ideas-notation-data-and-formulas/atomic-spectroscopy
// https://www.nist.gov/pml/atomic-spectra-database
struct Spectrum
{
static constexpr unsigned _num_points{ 7810 };
using Axis = std::array< double, _num_points >;
static constexpr Axis _x{ [] () // wavelength, nm
{
Axis a {};
for( unsigned i = 0; i < _num_points; ++i )
{
a[ i ] = 180 + 0.1 * i;
}
return a;
} () };
Axis _y {}; // radiance, W·sr−1·m−2
};
代码和变量的混用很难看,但至少公式就在reader眼前。任何其他解决方案都涉及大量输入以获得 in-class 定义的常量和类型。
或者如果我改变炉膛,我可以在运行时简单地 return lambda。
这里是完整的可编译代码:
#include <array>
template<int num_points>
static constexpr std::array<double, num_points> init_axis() {
std::array<double, num_points> a{};
for(int i = 0; i < num_points; ++i)
{
a[i] = 180 + 0.1 * i;
}
return a;
};
struct Z {
static constexpr int num_points = 10;
static constexpr auto axis = init_axis<num_points>();
};
为了完整起见,这里有一个不需要定义函数而是使用 lambda 的版本。 C++17 引入了在常量表达式中使用 lambda 的能力,因此您可以声明数组 constexpr
并使用 lambda 对其进行初始化:
static constexpr auto axis = [] {
std::array<double, num_points> a{};
for (int i = 0; i < num_points; ++i) {
a[i] = 180 + 0.1 * i;
}
return a;
}();
(注意最后一行的 ()
,它会立即调用 lambda。)
如果您不喜欢 axis
声明中的 auto
因为它使实际类型更难阅读,但又不想在 lambda 中重复该类型,你可以改为:
static constexpr std::array<double, num_points> axis = [] {
auto a = decltype(axis){};
for (int i = 0; i < num_points; ++i) {
a[i] = 180 + 0.1 * i;
}
return a;
}();
还有 std::index_sequence
技巧 (Wandbox example):
template <unsigned... i>
static constexpr auto init_axis(std::integer_sequence<unsigned, i...>) {
return std::array{(180 + 0.1 * i)...};
};
static constexpr auto axis = init_axis(std::make_integer_sequence<unsigned, num_points>{});