Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is calling a constexpr function with a member array not a constant expression?

I have the following helper function:

template<typename T, std::size_t N> constexpr std::size_t Length(const T(&)[N]) {     return N; } 

Which returns the length of a static array. In the past this always has worked but when I do this:

struct Foo {     unsigned int temp1[3];     void Bar()     {         constexpr std::size_t t = Length(temp1); // Error here     } }; 

I get an error when using MSVS 2017:

error C2131: expression did not evaluate to a constant  note: failure was caused by a read of a variable outside its lifetime  note: see usage of 'this' 

I was hoping someone can shed light on what I'm doing wrong.

like image 751
James Nguyen Avatar asked Jun 18 '18 20:06

James Nguyen


People also ask

Is constexpr constant?

The keyword constexpr was introduced in C++11 and improved in C++14. It means constant expression. Like const , it can be applied to variables: A compiler error is raised when any code attempts to modify the value.

Can a member function be constexpr?

const can only be used with non-static member functions whereas constexpr can be used with member and non-member functions, even with constructors but with condition that argument and return type must be of literal types.

Why does constexpr need to be static?

A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later.

Is constexpr implicitly const?

In C++11, constexpr member functions are implicitly const.


1 Answers

MSVC is correct. Length(temp1) is not a constant expression. From [expr.const]p2

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

  • this, except in a constexpr function or a constexpr constructor that is being evaluated as part of e;

temp1 evaluates this implicitly (because you are referring to this->temp1), and so you don't have a constant expression. gcc and clang accept it because they support VLAs as an extension (try compiling with -Werror=vla or -pedantic-errors).

Why isn't this allowed? Well, you could access the underlying elements and potentially modify them. This is completely fine if you are dealing with a constexpr array or an array that is being evaluated as a constant expression, but if you are not, then you cannot possibly have a constant expression as you will be manipulating values that are set at run time.

like image 175
Rakete1111 Avatar answered Sep 28 '22 03:09

Rakete1111