使用 C++17 填充 constexpr 数组

populating a constexpr array using C++17

我正在尝试通过以下方式使用 C++17 初始化 constexpr 数组:

template <size_t N>
struct CStr
{
    static constexpr std::array<int, N> getArr()
    {
        std::array<int, N> a;
        for (auto idx = 0; idx < a.size(); ++idx)
        {
            a[idx] = idx * idx;
        }
        return a;
    }
    static constexpr auto arr { getArr()};
};


int main()
{
    for (const auto &el : CStr<10>::arr)
    {
        std::cout << el << std::endl;
    }
}

然而,这会导致以下关于 getArr 不是 constexpr 函数的编译错误。谁能帮忙解释一下为什么?

<source>: In instantiation of 'constexpr const std::array<int, 10> CStr<10>::arr':
<source>:18:27:   required from 'struct CStr<10>'
<source>:24:35:   required from here
<source>:18:39: error: 'static constexpr std::array<int, N> CStr<N>::getArr() [with long unsigned int N = 10]' called in a constant expression
   18 |     static constexpr auto arr { getArr()};
      |                                 ~~~~~~^~
<source>:9:41: note: 'static constexpr std::array<int, N> CStr<N>::getArr() [with long unsigned int N = 10]' is not usable as a 'constexpr' function because:
    9 |     static constexpr std::array<int, N> getArr()
      |                                         ^~~~~~
<source>:12:9: error: 'goto' is not a constant expression
   12 |         for (auto idx = 0; idx < a.size(); ++idx)
      |         ^~~
Compiler returned: 1   |                                         ^~~~~

这是 C++20 之前的 C++ 限制,请参阅 Permitting trivial default initialization in constexpr contexts:您必须在 constexpr 函数内初始化所有变量。该标准给出了以下示例:

C++17

constexpr int uninit() {
  int a;                  // error: variable is uninitialized
  return a;
}

C++20

constexpr int uninit() {
  struct { int a; } s;
  return s.a;                   // error: uninitialized read of s.a
}

请注意,初始化本身在 C++20 中是可以的。读取不确定值(在“未初始化”对象内)是不正确的。


要解决您的问题,请初始化数组或切换到 C++20:

static constexpr std::array<int, N> getArr()
{
    std::array<int, N> a{}; // now initialized!
    for (auto idx = 0; idx < a.size(); ++idx)
    {
        a[idx] = idx * idx;
    }
    return a;
}