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?
If you pass a non-constexpr argument to the PlusOne function, the compiler can't evaluate it at compile-time, and it will simply be a normal run-time function. Hint: "The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time."
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.
Quick A: constexpr guarantees compile-time evaluation is possible if operating on a compile-time value, and that compile-time evaluation will happen if a compile-time result is needed.
A constexpr function is a function that can be invoked within a constant expression. A constexpr function must satisfy the following conditions: It is not virtual. Its return type is a literal type.
If the compiler is able to propagate constants up to the point where all arguments are constants, then the constexpr function will be evaluated at compile time. H Sutter said on Jan 14, 2013 03:48 PM: @chico: I didn't write the SO answer (I just edited it), but I'm not sure how it is different from Bjarne's one-line summary.
constexpr stands for constant expression and is used to specify that a variable or function can be used in a constant expression, an expression that can be evaluated at compile time. The key point of constexpr is that it can be executed at compile time.
Since it is possible that a function declared as constexpr can be called during run-time, under which criteria does the compiler decide whether to compute it at compile-time or during runtime? In this case, i is unknown at compile-time, which is probably the reason why the compiler treats POW () as a regular function which is called at runtime.
A constexpr function is evaluated at compile time if all its arguments are constant expressions. chico said on Jan 13, 2013 06:28 PM: ok, now we have B and H not agreeing how/when it should eval. confused.
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.
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