Given that the C++ standard library doesn't (currently) provide constexpr versions of the cmath functions, consider the program below.
#include <cmath>
#include <cstring>
int main()
{
constexpr auto a = std::pow(2, 10);
constexpr auto b = std::strlen("ABC");
}
As expected, MSVC++ and clang++ fail to compile this, because constexpr
variables are initialized from functions that are not declared constexpr
.
g++, however, compiles this. The version of g++ doesn't seem to matter.
(See them all in compiler explorer)
How does g++ achieve this? Is this correct (allowed) compiler behavior?
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.
constexpr functionsA 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.
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.
Try it on your code baseNot only will your code be faster and smaller, it'll be safer. Code marked constexpr can't bitrot as easily.
@Herb Sutter: The general expectation seems to be that constexpr functions are always evaluated at compile time. Cedric's comment is a clear example of that, he says "This is all about optimization". And hence expect that constexpr functions are always evaluated at compile time, regardless of its context. To me, they are all about expressiveness...
constexpr function can call only other constexpr function not simple function. The function should not be of a void type and some operators like prefix increment (++v) are not allowed in constexpr function. It removes the function calls as it evaluates the code/expressions in compile time.
GCC is a collection of compilers and libraries that offer support for various programming languages such as C, C++, Java, etc. The GCC compiler is included in most Linux distributions. In this article, we have used Ubuntu for all the examples. gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 Copyright (C) 2019 Free Software Foundation, Inc.
In C++ 11, a constexpr function should contain only one return statement. C++ 14 allows more than one statement. constexpr function should refer only to constant global variables. constexpr function can call only other constexpr function not simple function.
The resolution of LWG 2013 was that implementations are not allowed to declare non-constexpr
functions as constexpr
, so gcc is non-conformant by allowing these to be evaluated at compile time.
That said, GCC does not actually mark the needed functions as constexpr
. What it instead does is replace those calls very early on with __builtin_pow
and __builtin_strlen
, which it can compute at compile time (the std::
versions call the libc versions, which can't). This is a compiler extension.
If you compile with -fno-builtin
, it also fails to compile both std::pow
and std::strlen
, but you can make both clang and GCC compile this by explicitly writing out __builtin_pow(2, 10)
and __builtin_strlen("ABC")
.
As noted, the C++ standard library doesn't currently support constexpr
evaluation of cmath functions. However, that doesn't prevent individual implementations from having non-standard code. GCC has a nonconforming extension that allows constexpr
evaluation.
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