Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying a global variable in a constexpr function in C++17

In C++17, are you allowed to modify global variables in a constexpr function?

#include <iostream>  int global = 0;  constexpr int Foo(bool arg) {     if (arg) {         return 1;     }     return global++; }  int main() {     std::cout << global;     Foo(true);     std::cout << global;     Foo(false);     std::cout << global; } 

I wouldn't expect you to be able to, but clang 6 allows it: https://godbolt.org/g/UB8iK2

GCC, however, doesn't: https://godbolt.org/g/ykAJMA

Which compiler is correct?

like image 279
Drew Avatar asked Jun 27 '18 01:06

Drew


People also ask

Can constexpr be modified?

According to the proposal, an object created within a constexpr expression, can now be changed during the evaluation process - until the evaluation process or the object's lifetime ends.

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.

Does constexpr Impline inline variables?

The constexpr keyword implies inline.

What is a constexpr function C++?

A constexpr function is one whose return value is computable at compile time when consuming code requires it. Consuming code requires the return value at compile time to initialize a constexpr variable, or to provide a non-type template argument.


2 Answers

I'll add that dcl.constexpr/5 additionally requires:

For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression, or, for a constructor, a constant initializer for some object ([basic.start.static]), the program is ill-formed, no diagnostic required.

Since you deiberately wrote the function so that Foo(true) evaluates to a core constant expression, Foo(false) is not required to.

like image 22
Davislor Avatar answered Sep 20 '22 15:09

Davislor


Which compiler is correct?

Clang is right.

The definition of a constexpr function as per dcl.constexpr/3

The definition of a constexpr function shall satisfy the following requirements:

(3.1) its return type shall be a literal type;
(3.2) each of its parameter types shall be a literal type;
(3.3) its function-body shall be = delete, = default, or a compound-statement that does not contain:

(3.3.1) an asm-definition,
(3.3.2) a goto statement,
(3.3.3) an identifier label,
(3.3.4) a try-block, or
(3.3.5) a definition of a variable of non-literal type or of static or thread storage duration or for which no initialization is performed.

Also as per dcl.constexpr/5:

For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression,

Foo(true) could be evaluated to a core constant expression (i.e 1).

Also, Foo(false) could be but is not required to be constant evaluated.

CONCLUSION

Thus, a bug in GCC.


Many thanks to @Barry, @aschepler and @BenVoigt for helping me with this answer.
like image 130
Joseph D. Avatar answered Sep 19 '22 15:09

Joseph D.