I'm trying to understand the meaning of constexpr when applied to functions. In the example below the program compiles and runs but I don't understand how the function sum(int n) can be deduced at compile time as n is not known until run time. I'm using VS 2017 with latest updates.
The program compiles whether constexpr is included or not.
#include <iostream>
constexpr int sum(int n)
{
return (n <= 0) ? 0 : n + sum(n-1);
}
int main()
{
int i;
std::cin >> i;
std::cout << sum(i) << std::endl;
return 0;
}
I expected the compiler to error that sum(int n) is not a constant expression. Or is constepxr just a hint to the compiler like "inline", that it is free to ignore?
I expected the compiler to error that sum(int n) is not a constant expression.
constexpr int sum(int n); means that the function can be evaluated at compile time. It doesn't have to be. You can call it at runtime without any issues, which makes sense to not force programmers to duplicate code when they need identical functionality at runtime as well as at compile time.
With C++20, you'll be able to trigger the error you were expecting by qualifying the function with the new keyword consteval instead of constexpr.
consteval int sum(int n)
{
// As before...
}
int i;
// determine i at runtime...
sum(i); // Error! Not evaluated at compile time.
You can have a look at P1073 for this feature. This proposal has been approved for the next standard.
The constexpr keyword says that the function must be evaluated at compile time, if it's called in a constexpr context.
Consider:
constexpr int sum(int n)
{
return (n <= 0) ? 0 : n + sum(n-1);
}
int main()
{
int i;
std::cin >> i;
constexpr int s1 = sum(4); // OK, evaluated at compile time
int s2 = sum(i); // OK, evaluated at run time
constexpr int s3 = sum(i); // Error, i cannot be evaluated at compile time
int s4 = sum(4); // OK, execution time depends on the compiler's mood
}
Here, s3 is constexpr and so it's initializer needs to be evaluated at compile time. Hence the error.
If this feature weren't there, you would have to write two versions of your function, one for compile time use and the other for run-time use.
See it yourself on the Compiler Explorer.
Also note that constexpr implies inline for functions.
Here is what my perspective is
constexpr, ensures that the constant must be a compile-time constant
Thus
constexpr double pi (3.5); // is Okay because resolution is at compile time
and this
// Should be Okay be cause the resolution of **sum** is at compiletime
// evaluation however is run-time dependent
constexpr int sum(int n)
{
return (n <= 0) ? 0 : n + sum(n-1);
}
Another example is something like this
constexpr int compute(int x) {
return x+1;
}
int foo[compute(15)];
Related
I was playing around with constexpr in C++ and noticed a strange behavior that I wish to understand. Consider this code from 5.19 section of Standard.
constexpr int f1(int k) {
constexpr int x = k; // error: x is not initialized by a
// constant expression because lifetime of k
// began outside the initializer of x
return x;
}
As error states, lifetime of k began outside the initializer of x, thus we can't be sure that x will be a constant expression.
And here the another version of the same function.
constexpr int f1(int k) {
return k;
}
This one is totally fine and usable. So question is why, here also, the lifetime of k began outside of initializer of return value, or not, or this is because of RVO and technically if just follow the Standard this also should be an error?
And also another question, from which this one actually arise. I was trying to write constexpr IPv4 class. For that purpose I've used constructor with std::string_view. So I was able to have this in compile time using gcc 10.3 and -std=c++20
constexpr IPv4 myIP{"192.168.0.0"};
constexpr size_t count = myIP.countOfDots(); // calls std::count which is constexpr in C++20
Now I want to validate that IP is correct, so I need to check count of dots to be equal to 3, which I can easily do here by
if constexpr (count != 3)
The question is how to organize this into some function, which will also allow me to do such a check in compile time for any given IP, basically I want something like this
constexpr bool validateIP(const IPv4& ip);
And as in the example above, I can't just have this in that function
constexpr size_t count = ip.countOfDots();
So is it possible to do the way I want?
A function that's constexpr means that the function potentially can be evaluated at compile-time. The function must however also be callable with a run-time value, and produce a run-time result.
A variable that's constexpr has to be a compile time constant. Period.
What that means for your validateIP function is that you don't need to make count constexpr. You can write a function and mark it as constexpr.
When you call the function with a compile time constant, it will get evaluated at compile time.
If you call it with a run time value it will get evaluated at run time.
#include <string_view>
#include <iostream>
constexpr bool validateIP(const std::string_view& ip) {
int count = 0;
for (auto& c : ip) {
if (c == '.') {
++count;
}
}
return count == 3;
}
int main()
{
// Assigning the value to a constexpr is not needed to make the function
// be evaluated at compile time, but it proves that it is in this case
constexpr auto isValid1 = validateIP("123.456.789.0");
std::cout << isValid1;
}
I want to implement my_static_assert that slightly differs from c++17 single-parametric static_assert: if condition inside my_static_assert is not known at compile time, it should pass.
The second my_static_assert in the following example should pass but if I would use static_assert it will fail.
#include <iostream>
int x, y;
constexpr int f1() { return 0; }
constexpr int f2() { return 0; }
int f3() { return x; }
int f4() { return y; }
constexpr int sum(int a, int b) { return a + b; }
int main() {
std::cin >> x >> y;
// it should fail
my_static_assert(sum(sum(f1(), f2()), sum(f1(), f1())) != 0);
// it should pass
my_static_assert(sum(sum(f1(), f2()), sum(f4(), sum(f3(), f1()))) != 0);
}
If you want to know why this question arised:
I am building expressions using leaf functions f1,f2,f3,f4 and operations on the expression nodes: sum,mul,div,sub. Leafs that are known at compile time contain value that is always 0.
I am trying to check that my expressions contain at least one element that is not known at compile time.
If you are willing to commit to a compiler with GNU extensions, it's possible. So be warned.
It takes two overloads and a helper macro:
template<std::size_t N>
constexpr void assert_helpr(int(&)[N]) = delete;
void assert_helpr(...) {}
#define my_static_assert(...) do { \
__extension__ int _tmp [(__VA_ARGS__) + 1]; \
assert_helpr(_tmp); \
} while(0)
It works as follows:
The macro grabs your token soup and treats it like an integral expression. +1 is to avoid pathological zero cases.
If the expression is a constant expression, we get a standard array. Otherwise we get a VLA.
Now we call one of two overloaded functions. Overload resolution will always choose a c var-arg function last. If what we got was a regular array, the first, deleted overload is chosen, and the assertion fails.
If we got a VLA, the second overload is chosen and the assertion passes.
I haven't tested it thoroughly, but it seems to work on both Clang and GCC. See it live.
#Artyer was kind enough to share a solution based on this approach on godbolt.
Here's a reduction of that code to this problem:
template<std::size_t N>
constexpr std::false_type assert_helpr(int(&)[N]);
constexpr std::true_type assert_helpr(...);
#define my_static_assert(...) do { \
__extension__ int _tmp[(__VA_ARGS__) + 1]; \
static_assert(decltype(assert_helpr(_tmp)){}, #__VA_ARGS__); \
} while(0)
Same use of overloading, except this time we grab an actual result type from the call via decltype, and proceed to create a true compile time Boolean constant out of it.
This allows direct use of static_assert, and as a nice to have feature, we can pass it the stringified token soup to get an indication in the error of the expression that failed.
Since the extended versions of constexpr (I think from C++14) you can declare constexpr functions that could be used as "real" constexpr. That is, the code is executed at compile time or can behave as inline functions. So when can have this program:
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
return 0;
}
The result is:
7
7
7
So far so good.
Is there a way (possibly standard) to know inside foo(const int s) if the function is executed at compile time or at runtime?
EDIT: Also is it possible to know at runtime if a function was evaluated at compile time?
C++20 introduces is_constant_evaluated, defined in header <type_traits>, which addresses this issue.
constexpr int foo(int s)
{
if (std::is_constant_evaluated()) // note: not "if constexpr"
/* evaluated at compile time */;
else
/* evaluated at run time */;
}
Note that here the ordinary if is used instead of if constexpr. If you use if constexpr, then the condition has to be evaluated at compile time, so is_constant_evaluated always returns true, rendering the test useless.
The technique listed works, but since it uses static_assert it is not sfinae friendly. A better way (in theory, you'll see what I mean) to do this is to check whether a function is noexcept. Why? Because, constant expressions are always noexcept, even if the functions are not marked as such. So, consider the following code:
template <class T>
constexpr void test_helper(T&&) {}
#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))
test_helper is constexpr, so it will be a constant expression as long as its argument is. If it's a constant expression, it will be noexcept, but otherwise it won't be (since it isn't marked as such).
So now let's define this:
double bar(double x) { return x; }
constexpr double foo(double x, bool b) {
if (b) return x;
else return bar(x);
}
foo is only noexcept if the x is a constant expression, and b is true; if the boolean is false then we call a non constexpr function, ruining our constexpr-ness. So, let's test this:
double d = 0.0;
constexpr auto x = IS_CONSTEXPR(foo(3.0, true));
constexpr auto y = IS_CONSTEXPR(foo(3.0, false));
constexpr auto z = IS_CONSTEXPR(foo(d, true));
std::cerr << x << y << z;
It compiles, great! This gives us compile time booleans (not compile failures), which can be used for sfinae, for example.
The catch? Well, clang has a multi-year bug, and doesn't handle this correctly. gcc however, does. Live example: http://coliru.stacked-crooked.com/a/e7b037932c358149. It prints "100", as it should.
I think the canonical way to do that is with static_assert. static_asserts are evaluated at compile time, so they will break the build if their condition is false.
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
static_assert(foo(3) == 7, "Literal failed");
static_assert(foo(bar) == 7, "const int failed");
static_assert(foo(a) == 7, "constexpr int failed");
return 0;
}
clang++ -std=c++14 so1.cpp compiles fine for me, showing that everything works as expected.
If you can use C++20, there is std::is_constant_evaluated which does exactly what you want. std::is_constant_evaluated is typically implemented using a compiler intrinsic.
This is called __builtin_is_constant_evaluated in GCC and clang, so you can implement your own "safe" wrapper around it, even in C++17 and lower.
// if C++20, we will need a <type_traits> include for std::is_constant_evaluated
#if __cplusplus >= 202002L
#include <type_traits>
#endif
constexpr bool is_constant_evaluated() {
#if __cplusplus >= 202002L
return std::is_constant_evaluated();
#elif defined(__GNUC__) // defined for both GCC and clang
return __builtin_is_constant_evaluated();
#else
// If the builtin is not available, return a pessimistic result.
// This way callers will implement everything in a constexpr way.
return true;
#endif
}
Note that this builtin is still relatively new (GCC 9.0+) so you might also want to detect the compiler version.
Within a constexpr function, you couldn't tell if you are being evaluated in a constexpr context prior to c++20. Since c++20, this functionalty was added -- constexpr bool std::is_constant_evaluated() will tell you if you are being called in a constexpr context.
Outside a constexpr function, there are a number of ways to determine if a call to a function with a certain set of arguments would be evaluated in a constexpr context. The easiest would be to use the result in a context requiring constexpr.
Assuming your constexpr expression returns a non-void integral or pointer type (including function pointer):
#define CONSTEXPR_EVAL(...) \
std::integral_constant< \
std::decay_t<decltype(__VA_ARGS__)>, \
__VA_ARGS__ \
>::value
then CONSTEXPR_EVAL( bar(foo, true) ) will fail to compile if bar(foo, true) cannot be evaluated at compile time, and if it can be evaluated at compile time it returns that value.
Other tricks involving noexcept (a function evaluated at compile time is noexcept) can work (see #NirFriedman's answer).
Based on the information in this discussion, I crafted the following minimal example:
template <class T>
constexpr void test_helper(T &&) {}
#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))
constexpr void test(){
static_assert(IS_CONSTEXPR(10), "asdfadsf");
constexpr const int x = 10;
static_assert(IS_CONSTEXPR(x), "asdfadsf");
int y;
static_assert(IS_CONSTEXPR(y), "asdfadsf");
}
int main(){
test();
return 0;
}
To my disappointment, It it fails to compile at each of the static_asserts. see https://www.godbolt.org/z/Tr3z93M3s
Sorry for spoiling the party, but there is certainly no standard way of doing this. Under the as-if rule, the compiler could emit code that calculates the result at run time even in such cases where it has already been forced to calculate it at compile time in a different context. Anything that can be done at compile time can be done again at run time, right? And the calculation has already been proven not to throw.
By extension, then, any standard-compliant IS_REALLY_CONSTEXPR or is_really_constexpr check cannot disprove that the exact same call, or for that matter, the value of the exact same constexpr symbol involves a run time calculation.
Of course there usually isn't any reason to repeat a calculation at run time that can be done or even has already been done at compile time, but the question was about telling whether the compiler uses the precalculated result, and there isn't one.
Now you did say possibly standard, so in effect your best bet is probably to test one of the provided solutions with your compiler of choice and hope that it behaves consistently. (Or reading the source code if it is open/public source and you are so inclined.)
Since the extended versions of constexpr (I think from C++14) you can declare constexpr functions that could be used as "real" constexpr. That is, the code is executed at compile time or can behave as inline functions. So when can have this program:
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
return 0;
}
The result is:
7
7
7
So far so good.
Is there a way (possibly standard) to know inside foo(const int s) if the function is executed at compile time or at runtime?
EDIT: Also is it possible to know at runtime if a function was evaluated at compile time?
C++20 introduces is_constant_evaluated, defined in header <type_traits>, which addresses this issue.
constexpr int foo(int s)
{
if (std::is_constant_evaluated()) // note: not "if constexpr"
/* evaluated at compile time */;
else
/* evaluated at run time */;
}
Note that here the ordinary if is used instead of if constexpr. If you use if constexpr, then the condition has to be evaluated at compile time, so is_constant_evaluated always returns true, rendering the test useless.
The technique listed works, but since it uses static_assert it is not sfinae friendly. A better way (in theory, you'll see what I mean) to do this is to check whether a function is noexcept. Why? Because, constant expressions are always noexcept, even if the functions are not marked as such. So, consider the following code:
template <class T>
constexpr void test_helper(T&&) {}
#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))
test_helper is constexpr, so it will be a constant expression as long as its argument is. If it's a constant expression, it will be noexcept, but otherwise it won't be (since it isn't marked as such).
So now let's define this:
double bar(double x) { return x; }
constexpr double foo(double x, bool b) {
if (b) return x;
else return bar(x);
}
foo is only noexcept if the x is a constant expression, and b is true; if the boolean is false then we call a non constexpr function, ruining our constexpr-ness. So, let's test this:
double d = 0.0;
constexpr auto x = IS_CONSTEXPR(foo(3.0, true));
constexpr auto y = IS_CONSTEXPR(foo(3.0, false));
constexpr auto z = IS_CONSTEXPR(foo(d, true));
std::cerr << x << y << z;
It compiles, great! This gives us compile time booleans (not compile failures), which can be used for sfinae, for example.
The catch? Well, clang has a multi-year bug, and doesn't handle this correctly. gcc however, does. Live example: http://coliru.stacked-crooked.com/a/e7b037932c358149. It prints "100", as it should.
I think the canonical way to do that is with static_assert. static_asserts are evaluated at compile time, so they will break the build if their condition is false.
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
static_assert(foo(3) == 7, "Literal failed");
static_assert(foo(bar) == 7, "const int failed");
static_assert(foo(a) == 7, "constexpr int failed");
return 0;
}
clang++ -std=c++14 so1.cpp compiles fine for me, showing that everything works as expected.
If you can use C++20, there is std::is_constant_evaluated which does exactly what you want. std::is_constant_evaluated is typically implemented using a compiler intrinsic.
This is called __builtin_is_constant_evaluated in GCC and clang, so you can implement your own "safe" wrapper around it, even in C++17 and lower.
// if C++20, we will need a <type_traits> include for std::is_constant_evaluated
#if __cplusplus >= 202002L
#include <type_traits>
#endif
constexpr bool is_constant_evaluated() {
#if __cplusplus >= 202002L
return std::is_constant_evaluated();
#elif defined(__GNUC__) // defined for both GCC and clang
return __builtin_is_constant_evaluated();
#else
// If the builtin is not available, return a pessimistic result.
// This way callers will implement everything in a constexpr way.
return true;
#endif
}
Note that this builtin is still relatively new (GCC 9.0+) so you might also want to detect the compiler version.
Within a constexpr function, you couldn't tell if you are being evaluated in a constexpr context prior to c++20. Since c++20, this functionalty was added -- constexpr bool std::is_constant_evaluated() will tell you if you are being called in a constexpr context.
Outside a constexpr function, there are a number of ways to determine if a call to a function with a certain set of arguments would be evaluated in a constexpr context. The easiest would be to use the result in a context requiring constexpr.
Assuming your constexpr expression returns a non-void integral or pointer type (including function pointer):
#define CONSTEXPR_EVAL(...) \
std::integral_constant< \
std::decay_t<decltype(__VA_ARGS__)>, \
__VA_ARGS__ \
>::value
then CONSTEXPR_EVAL( bar(foo, true) ) will fail to compile if bar(foo, true) cannot be evaluated at compile time, and if it can be evaluated at compile time it returns that value.
Other tricks involving noexcept (a function evaluated at compile time is noexcept) can work (see #NirFriedman's answer).
Based on the information in this discussion, I crafted the following minimal example:
template <class T>
constexpr void test_helper(T &&) {}
#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))
constexpr void test(){
static_assert(IS_CONSTEXPR(10), "asdfadsf");
constexpr const int x = 10;
static_assert(IS_CONSTEXPR(x), "asdfadsf");
int y;
static_assert(IS_CONSTEXPR(y), "asdfadsf");
}
int main(){
test();
return 0;
}
To my disappointment, It it fails to compile at each of the static_asserts. see https://www.godbolt.org/z/Tr3z93M3s
Sorry for spoiling the party, but there is certainly no standard way of doing this. Under the as-if rule, the compiler could emit code that calculates the result at run time even in such cases where it has already been forced to calculate it at compile time in a different context. Anything that can be done at compile time can be done again at run time, right? And the calculation has already been proven not to throw.
By extension, then, any standard-compliant IS_REALLY_CONSTEXPR or is_really_constexpr check cannot disprove that the exact same call, or for that matter, the value of the exact same constexpr symbol involves a run time calculation.
Of course there usually isn't any reason to repeat a calculation at run time that can be done or even has already been done at compile time, but the question was about telling whether the compiler uses the precalculated result, and there isn't one.
Now you did say possibly standard, so in effect your best bet is probably to test one of the provided solutions with your compiler of choice and hope that it behaves consistently. (Or reading the source code if it is open/public source and you are so inclined.)
Ok, this might be a stupid question, but I completely don't understand chapter 12.1.6.2 - conditional evaluation under constexpr functions of the c++ programming language. This is the whole very short text.
A branch of a conditional expression that is not taken in a constexpr
function is not evaluated. This implies that a branch not taken can
require run-time evaluation. For example:
constexpr int check(int i)
{
return (low<=i && i<high) ? i : throw out_of_range();
}
constexpr int low = 0;
constexpr int high = 99;
// ...
constexpr int val = check(f(x,y,z));
You might imagine low and high to be configuration parameters that are
known at compile time, but not at design time, and that f(x,y,z)
computes some implementation-dependent value.
Source for context
I tried running the code above to try to more understand the explanation but I'm getting an error. Can someone provide a clearer explanation?
Edit: I created a program to test this:
#include<iostream>
#include<stdexcept>
using namespace std;
constexpr int low = 0;
constexpr int high = 99;
constexpr int check(int i) {
return (low<=i && i<high) ? i : throw out_of_range();
}
constexpr int f(int x, int y, int z) {
return x*y*z;
}
int main() {
constexpr int val = check(f(2,2,2));
cout << val << '\n';
}
It won't run:
no matching function for call to 'std::out_of_range::out_of_range()' //I'm really surprised at this
return (low<=i && i<high) ? i : throw out_of_range();
error: body of constexpr function 'constexpr int check(int)' not a return-statement
}
error: 'constexpr int check(int)' called in a constant expression
constexpr int val = check(f(2,2,2));
It means that a conditional branch in a constexpr function is allowed to use non-constant expressions (i.e. ones requiring run-time evaluation, such as throwing exceptions) as long as that branch is never taken when the function is called in a constant expression context.
So it's OK to call check to initialized the constexpr variable val, as long as the arguments to the function are constant expressions, and the condition (low<=i && i<high) is true.
If the arguments are not constants, the function call is not a constant expression and so can't initialize a constexpr variable.
If the condition is false the function needs to take the false branch, which needs to throw an exception, which requires run-time evaluation, so the function is not a constant expression, and so cannot initialize a constexpr variable.
When the argument is a constant expression, the compiler knows at compile-time whether the branch will be taken, so as long as the condition is true it can completely ignore the false branch, and doesn't complain that throwing exceptions is impossible at compile-time.
When the function is called at run-time, it can have any arguments, and the false branch can be taken and the throw will be evaluated as for a normal (non-constexpr) function.