28

I am having trouble understanding why both gcc-8.2.0 and clang-7.0.0 reject the following code (live code here):

#include <array>

int main() {

    constexpr std::array<int,3> v{1,2,3};
    constexpr auto b = v.begin(); // error: not a constexpr 
    return 0;
}

with the error

error: '(std::array<int, 3>::const_pointer)(& v.std::array<int,3>::_M_elems)' 
is not a constant expression (constexpr auto b = v.begin();)

According to en.cppreference.com, the begin() member function is declared constexpr. Is this a compiler bug?

4
  • use .cbegin . Commented Oct 24, 2018 at 15:23
  • 3
    @АлексейНеудачин makes no difference. Commented Oct 24, 2018 at 15:23
  • @АлексейНеудачин begin() and cbegin() do the same thing on const objects. Commented Oct 24, 2018 at 15:25
  • so try auto b=... and then if it fails const . also you change auto to std::....::citerator Commented Oct 24, 2018 at 15:27

1 Answer 1

48

So let's sidestep std::array to make this a bit easier:

template <typename T, size_t N>
struct array {
    T elems[N];

    constexpr T const* begin() const { return elems; }
};

void foo() {
    constexpr array<int,3> v{{1, 2, 3}};
    constexpr auto b = v.begin(); // error
}

constexpr array<int, 3> global_v{{1, 2, 3}};
constexpr auto global_b = global_v.begin(); // ok

Why is b an error but global_b is okay? Likewise, why would b become okay if we declared v to be static constexpr? The problem is fundamentally about pointers. In order to have a constant expression that's a pointer, it has to point to one, known, constant thing, always. That doesn't really work for local variables without static storage duration, since they have fundamentally mutable address. But for function-local statics or globals, they do have one constant address, so you can take a constant pointer to them.


In standardese, from [expr.const]/6:

A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:

  • if the value is an object of class type, [...]
  • if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object ([expr.add]), the address of a function, or a null pointer value, and
  • [...]

b is none of those things in the second bullet, so this fails. But global_b satisfies the bolded condition - as would b if v were declared static.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.