Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

As of C++17, std::array<T,N>::begin() is constexpr:

constexpr iterator begin() noexcept;

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

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

Is perfectly legal code (although maybe a bit useless). The start of the underlying array and thus the iterator depend on the malloc'd address.

I have the sense that I am under a misapprehension of what constexpr does as I don't see how any non-static member function could possibly be constexpr, especially if it (transitively) accesses data members.

like image 490
bitmask Avatar asked Jan 01 '23 03:01

bitmask


2 Answers

constexpr functions can be called in non-compiletime-constant expressions. Such calls are evaluated at runtime. Only when constexpr function is called in a compiletime-constant expression, is the function evaluated at compile time.

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

It can be known at compile time when the array itself is a compile time constant.

The fact that it cannot be known at compile time when the array is not a compile time constant is not a problem because the function is executed at runtime in that case.

like image 124
eerorika Avatar answered Jan 11 '23 11:01

eerorika


You do not need the unique pointer to see the effect of compile time vs runtime evaluation. This does compile:

#include <array>

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

But this does not:

#include <array>

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

Error:

<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};

Sloppy speaking, the constexpr of begin() means that it is possible to evaluate the method at compile time on a constexpr object. For the non-constexpr array, the method is evaluated at runtime. Hence p.begin() cannot be used to initialize the constexpr it.

like image 42
463035818_is_not_a_number Avatar answered Jan 11 '23 11:01

463035818_is_not_a_number