(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.
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.
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.
You're not actually "calling" f
at compile time.
if your main function included: static_assert(f() == 1, "f() returned 1");
I suspect you would get an "f() is not a constant expression" error.
Here's a related question
The standard requires that a constexpr
function actually be evaluable at compile time for some set of parameters but not all. It does not require compilers to diagnose a constexpr
function doing certain things which might be non-compile-time in some circumstances, or even whether such a function has such a set of parameters. This avoids them having to solve the halting problem.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.