为什么 std::array<T,N>::begin() 自 C++17 以来是一个 constexpr?

Why is std::array<T,N>::begin() a constexpr since C++17?

从 C++17 开始,std::array<T,N>::begin() 是 constexpr:

constexpr iterator begin() noexcept;

但是begin的return怎么可能在编译时就知道呢?例如:

int main() {
  auto p = std::make_unique<std::array<int,2>>();
  auto it = p->begin();
}

是完全合法的代码(虽然可能有点没用)。底层数组的开始以及迭代器取决于 malloc 的地址。

我觉得我对 constexpr 的作用有误解,因为我不明白 any 非静态成员函数可能是 constexpr,尤其是当它(传递地)访问数据成员时。

constexpr 函数可以在非编译时常量表达式中调用。此类调用在运行时进行评估。只有在编译时常量表达式中调用 constexpr 函数时,才会在编译时计算函数。

But how can the return of begin be known at compile time?

当数组本身是一个编译时常量时,在编译时就可以知道

当数组不是编译时常量时在编译时无法获知这一事实不是问题,因为在这种情况下函数是在运行时执行的。

您不需要唯一指针来查看编译时与运行时评估的效果。这确实编译:

#include <array>

int main() {
  static constexpr std::array<int,2> p{1,2};
  constexpr auto it = p.begin();
}

但这不是:

#include <array>

int main() {
  std::array<int,2> p{1,2};
  constexpr auto it = p.begin();
}

错误:

<source>:5:18: error: constexpr variable 'it' must be initialized by a constant expression

  constexpr auto it = p.begin();    
                 ^    ~~~~~~~~~    
<source>:5:18: note: pointer to subobject of 'p' is not a constant expression    
<source>:4:21: note: declared here    
  std::array<int,2> p{1,2};

马虎地说,begin()constexpr意味着可以在constexpr对象上在编译时评估该方法。对于非 constexpr 数组,该方法在运行时计算。因此 p.begin() 不能用于初始化 constexpr it.

此更改解决的问题是能够在 constexpr 函数中使用 non-const std::array 来计算某些结果。回想一下,constexpr 函数在编译时计算时不能调用非 constexpr 函数。

作为一个例子,考虑一个计算 i = 1 到 N 之和的函数。为了论证,考虑一个非常愚蠢的方法(现实世界中存在非愚蠢的例子,但比this): 创建一个用 {1, 2, 3, ...} 初始化的数组,然后返回 array.

的元素之和
// Compute sum from i = 1 to N
template <unsigned N>
unsigned
sum() noexcept
{
    std::array<unsigned, N> a{};
    unsigned u = 1;
    for (auto i = a.begin(); i != a.end(); ++i, ++u)
        *i = u;
    u = 0;
    for (auto const x : a)
        u += x;
    return u;
}

这很好用,可以这样调用:

auto x = sum<5>();  // x == 15

现在有人说:嘿,让我们在编译时计算这个!

在 C++17 中,这就像将 constexpr 打到 sumx:

上一样简单
// Compute sum from i = 1 to N
template <unsigned N>
constexpr
unsigned
sum() noexcept
...

constexpr auto x = sum<5>();  // x == 15

但是在 C++14 中这不能编译:

test.cpp:24:20: error: constexpr variable 'x' must be initialized by a constant expression
    constexpr auto x = sum<5>();
                   ^   ~~~~~~~~
test.cpp:11:21: note: non-constexpr function 'begin' cannot be used in a constant expression
    for (auto i = a.begin(); i != a.end(); ++i, ++u)
                    ^

它无法编译的原因是 array<T, N>::begin() 不是 constexpr 函数。