Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What determines whether a constexpr function is a constant expression?

(compiler used is gcc with c++17 as far as I know (difficult to find this in visual studio))

#include <iostream>  using namespace std;  void increment( int& v ) {     ++v; }  int constexpr f() {     int v = 0;     increment( v );     return v; }  int main( ) {     cout << f( ) << '\n'; } 

The above code gives the error on compile:

constexpr function 'f' cannot result in a constant expression.

As I understand it this is because the function increment is not a constexpr. What confuses me is that the following code compiles fine:

#include <iostream>  using namespace std;  void increment( int& v ) {     ++v; }  int constexpr f() {     int v = 0;     for( int i = 0; i < 1; ++i )     {         increment( v );     }        return v; }  int main( ) {     cout << f( ) << '\n'; } 

This code is functionally the same and it does compile, even though increment is still not a constexpr. I don't understand how it's possible that a for-loop through the range [0, 1) causes the compiler to realize that the function f actually is a constexpr.

If anyone can give some insights on constexpr in c++ and this apparent inconsistency, I'd greatly appreciate it.

like image 571
mchl12 Avatar asked Nov 30 '20 22:11

mchl12


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.

How do I know if a function is constexpr?

The easiest way to check whether a function (e.g., foo ) is constexpr is to assign its return value to a constexpr as below: constexpr auto i = foo(); if the returned value is not constexpr compilation will fail.

What does constexpr const mean?

constexpr creates a compile-time constant; const simply means that value cannot be changed.

Why is constexpr over const?

const can only be used with non-static member function 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.


2 Answers

Both programs are "ill-formed no diagnostic required", per [dcl.constexpr]/6:

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, an evaluated subexpression of the initialization full-expression of some constant-initialized object ([basic.start.static]), the program is ill-formed, no diagnostic required.

It's a bit strange that gcc just fails to notice the issue with the second program, but it's still conforming.

Note a diagnostic would be required if f were used in a context that actually requires a constant expression, for example constexpr int n = f();.

Some things are never permitted in a constexpr function. These do require a diagnostic (typically an error message), even if the function is never used in a constant expression - see cigien's answer. But the programs in the question don't violate any of these stricter rules.

like image 108
aschepler Avatar answered Sep 19 '22 15:09

aschepler


Since you're not calling f in a constant expression, your question is asking if the compiler is required to diagnose that f can't be called in a constant expression, based solely on its definition.

The requirements on the definition of a constexpr function are enumerated here:

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

(3.1) its return type (if any) shall be a literal type;

(3.2) each of its parameter types shall be a literal type;

(3.3) it shall not be a coroutine;

(3.4) if the function is a constructor or destructor, its class shall not have any virtual base classes;

(3.5) its function-body shall not enclose

(3.5.1) a goto statement,

(3.5.2) an identifier label,

(3.5.3) a definition of a variable of non-literal type or of static or thread storage duration.

As can be seen, the definition of f does not violate any of the requirements in the list. So a compiler is conforming if it chooses not to diagnose this.

As pointed out in aschepler's answer, constexpr functions like f that can't be called in a constant expression, but are not diagnosable as such, are considered ill-formed-no-diagnostic-required.

like image 40
cigien Avatar answered Sep 20 '22 15:09

cigien