Let's take this simple example:
#include <iostream>
namespace foo {
constexpr int main(int argc, char* argv[]) {
// code
}
}
int main(int argc, char* argv[])
{
return foo::main(argc, argv);
}
Depend on what code is, clang will complain or no. If code is:
cout << "Hello!";
return 0;
clang complains:
error: constexpr function never produces a constant expression [-Winvalid-constexpr]
constexpr int main(int argc, char* argv[]) {
note: non-constexpr function 'operator<< >' cannot be used in a constant expression
std::cout << "Hello!";
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/ostream:530:5: note: declared here
operator<<(basic_ostream<char, _Traits>& __out, const char* __s)
Fair enough, constexpr functions can't contain any cout statements, as we know. But what happens if we do this?
for (int i = 0; i < argc; i++)
std::cout << argv[i];
clang allows it! OK, but this can't possibly be a constexpr function even though it is marked constexpr, let's try to use it in constexpr context.
int arr[foo::main(argc, argv)];
It works! So it must be clang bug? Reason I say clang because gcc complains:
error: body of constexpr function 'constexpr int foo::main(int, char**)' not a return-statement
So my conclusion is clang is wrong and gcc is right.
constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.
A constexpr function that is eligible to be evaluated at compile-time will only be evaluated at compile-time if the return value is used where a constant expression is required. Otherwise, compile-time evaluation is not guaranteed.
#define directives create macro substitution, while constexpr variables are special type of variables. They literally have nothing in common beside the fact that before constexpr (or even const ) variables were available, macros were sometimes used when currently constexpr variable can be used.
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.
Clang is correct here.
First example
Here, the code is:
constexpr int foo::main(int argc, char* argv[]) {
std::cout << argv[i];
return 0;
}
In C++11, this code is ill-formed, because the body contains an expression-statement, which is not permitted in a constexpr
function definition.
In C++1y, this code is ill-formed with no diagnostic required, because a call to foo::main
can never produce a constant expression (because it always calls operator<<(std::ostream&, const char*)
, which is not constexpr
).
Second example
In this case, the code is:
constexpr int foo::main(int argc, char* argv[]) {
for (int i = 0; i < argc; i++)
std::cout << argv[i];
return 0;
}
In C++11, this code is ill-formed, because it contains a for
-statement.
In C++1y, this code is valid. In particular, foo::main(0, 0)
is a constant expression (with value 0
). Since foo::main
is usable in a constant expression, Clang is not permitted to reject it, and does not do so.
Third example
int arr[foo::main(argc, argv)];
The array bound here is not a constant expression (because it reads argc
and argv
, which are not constant). However, Clang supports variable-length arrays as an extension by default. You can specify -pedantic-errors
to put clang into strictly-conforming mode, and in that mode it will reject this code.
GCC's diagnostic:
error: body of constexpr function 'constexpr int foo::main(int, char**)' not a return-statement
is incorrect in both C++11 and C++1y. In C++11, it's incorrect because the rule is more subtle (the body of a constexpr
function can contain typedef
s and a few other constructs, not just return
-statements). In C++1y, the rule no longer exists at all.
You compile your code in C++1y mode which contains wording to relax constexpr
restrictions including all looping statements.
Have a look at N3652 which introduced these changes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With