我无法以编程方式初始化静态 constexpr
std::array
成员。#include <array>
constexpr std::size_t N = 3;
using Mat = std::array<double, N * N>;
// OK, can initialize a free constexpr Mat
constexpr Mat InitEye() noexcept {
Mat TmpEye{0};
for (std::size_t r = 0; r < N; ++r) {
for (std::size_t c = 0; c < N; ++c) {
TmpEye[r * N + c] = (r == c) ? 1. : 0.;
}
}
return TmpEye;
}
// KO
class Wrapper {
private:
// KO cannot use it to initialize static constexpr member
static constexpr Mat WrappedInitEye() noexcept {
Mat TmpEye{0};
for (std::size_t r = 0; r < N; ++r) {
for (std::size_t c = 0; c < N; ++c) {
TmpEye[r * N + c] = (r == c) ? 1. : 0.;
}
}
return TmpEye;
}
public:
static constexpr Mat Eye = WrappedInitEye();
};
// also KO
class Wrapper2 {
public:
// OK in C++17, still KO in C++17 due to lack of constexpr access operator
static constexpr Mat Eye = [] {
Mat TmpEye{0};
for (std::size_t r = 0; r < N; ++r) {
for (std::size_t c = 0; c < N; ++c) {
TmpEye[r * N + c] = (r == c) ? 1. : 0.;
}
}
return TmpEye;
}();
};
int main() {
constexpr Mat Eye = InitEye();
constexpr Mat Eye2 = Wrapper::Eye;
return 0;
}
我找到的最接近的答案是这个(因此是上面的 lambda 版本)。
但是现场示例 si 显示了两个问题:
\<source\>:32:46: error: 'static constexpr Mat Wrapper::WrappedInitEye()' called in a constant expression before its definition is complete
32 | static constexpr Mat Eye = WrappedInitEye();
constexpr
的
std::array
非 lambda 版本给出了这个 “不完整的定义” 错误,因为:
但是,如何使用 C++14 实现编程式
std::array
初始化?
- 为什么非 lambda 版本会出现“不完整定义”错误?
因为静态成员函数
WrappedInitEye
的定义要到类定义结束时才算完成。我不太确定标准中的哪个位置解决了这个问题,但是如果您将 WrappedInitEye
设为自由函数,那么该特定错误就会消失。
- 如何使用 C++14 实现编程式
初始化?std::array
我在 C++14 中能做的最好的事情是:
#include <array>
#include <utility>
constexpr std::size_t N = 3;
using Mat = std::array<double, N * N>;
template<std::size_t Index>
static constexpr bool condition = Index / N == Index % N;
template<std::size_t Index>
constexpr auto genElement(char(*)[condition<Index>] = 0) -> double {
return 1.;
}
template<std::size_t Index>
constexpr auto genElement(char(*)[!condition<Index>] = 0) -> double {
return 0.;
}
template<std::size_t... Indices>
constexpr auto gen(std::index_sequence<Indices...>) {
return Mat{ genElement<Indices>()... };
}
int main() {
constexpr Mat a = gen(std::make_index_sequence<N*N>());
}
它仅适用于您的特定模式(单位矩阵,因此
Index / N == Index % N
时为 1,否则为 0),但您也许可以修改它以适应更复杂的模式。 char(*)[condition<Index>()] = 0
部分使用SFINAE。我从这里得到的。
您还可以使用标签调度:
template<std::size_t Index>
using Condition = std::integral_constant<bool, Index / N == Index % N>;
template<std::size_t Index>
constexpr auto genElement(std::true_type) -> double {
return 1.;
}
template<std::size_t Index>
constexpr auto genElement(std::false_type) -> double {
return 0.;
}
template<std::size_t... Indices>
constexpr auto gen(std::index_sequence<Indices...>) {
return Mat{ genElement<Indices>(Condition<Indices>{})... };
}