I was investigating some rather weird code-coverage results of constexpr functions (compile-time calls can't get instrumented by the code-coverage tool I use), and noticed that some constexpr functions were getting called as runtime functions, if the results of the function call were not stored.
It seems that, for constexpr functions or methods, if you store the results of the call (either in a runtime variable [emphasis!!!] or a constexpr variable), the call is a compile-time call (as long as the parameters are compile-time). If you ignore the results, the call is a runtime call. This has nothing to do with my code-coverage tool; the behavior seems to be repeatable in the simple example below.
You could argue that since constexpr functions cannot have side-effects, it doesn't matter what the compiler does if you don't return / use a result. I'd think that for efficiency, the compiler would still make whatever it can be constexpr, but that's neither here nor there... What I'm wondering is if this is even defined behavior.
Is this a portable way to guarantee your constexpr functions will be invoked as runtime??? There aren't a ton of uses for that, but one use is: if you want to "take credit for tests that were called on constexpr functions" in code coverage, by just calling the same function at the end of your unit test, and ignoring the result, so that they get instrumented.
There are other ways to force a function to get called as runtime, I know, I'm mostly curious about what's going on here. It was very unexpected when I first saw it. Unless this is portable, I'll probably just call my constexpr methods through a runtime object (which seems to do the trick even for static methods), or through a runtime function pointer.
See example below. Live demo: https://onlinegdb.com/rJao0RNGP
// Modified from https://stackoverflow.com/a/40410624/12854372
extern bool no_symbol;
struct ContextIsConstexpr {
size_t s;
constexpr ContextIsConstexpr() : s(1) {}
constexpr void operator()() {
auto ignore = s ? 1 : no_symbol;
}
};
constexpr bool tryIgnoringResult()
{
ContextIsConstexpr()();
return true;
}
constexpr void thereIsNoResult() {
ContextIsConstexpr()();
}
int main()
{
constexpr auto result1 = tryIgnoringResult(); // OK, compile-time
auto result2 = tryIgnoringResult(); // OK, compile-time
// tryIgnoringResult(); // Unexpected, runtime!
// thereIsNoResult(); // Unexpected, runtime!
}
It might be confusing, but constexpr functions should be called at compile time only in constexpr contexts (assignation to constexpr variable, use for array size or template parameter, ...).
In regular context, functions are called at runtime. Optimizer might resolve that function at compile time (as for any other functions following the as-if rule). constexpr is indeed a good hint for optimization to happen.
You could argue that since constexpr functions cannot have side-effects
They can have side effect, see following valid example:
constexpr int f(int i)
{
if (i == 0) return 0;
std::cout << i << std::endl;
return i;
}
int main()
{
[[maybe_unused]] constexpr int zero = f(0); // Compile time
f(42); // runtime
}
Demo
Related
see the following snippet:
struct config {
int x;
constexpr int multiply() const {
return x*3;
}
};
constexpr config c = {.x = 1};
int main() {
int x = c.multiply();
return x;
}
If I compile this with clang and -O0 I get a function call to multiply even though the object c and the function are marked constexpr. If I compile it with -O1 everything gets optimized as expected. Gcc on the other hand generates no call to multiply.
If I change the main to:
int main() {
constexpr auto y = c.multiply();
int x = y;
return x;
}
If I compile this with clang and -O0 I get not function call and the value 3 directly as stack variable. The -O1 result is the same as above.
So my question is: Does the constexpr evaluation depend on the compiler level? I would expect that in the example 1 the call to multiply would be constexpr and performed compile time. (like gcc does)
BR,
go2sh
See https://godbolt.org/z/WvPE5W77h
The Standard just requires that a call to constexpr is evaluated at compile time if the arguments are constexpr and the result must be constexpr due to context. Basically just forcing more restrictions on the author of the function, thus allowing it to be used in constexpr contexts.
Meaning y in second snippet forces evaluation at compile time. On the other hand, x in the first is an ordinary run-time call.
But the as-if rule applies here - as long as the observable effects of the program remain the same, the compiler can generate any instructions it wants. It can evaluate any function, even non-constexpr ones if it can do so - happens in practice often with constants propagation.
Yes, in general, higher optimization levels will inline more code and push more evaluation to the compile time. But "looking at the assembly" is not an observable effect in the sense above so there are no guarantees. You can use inline to give a hint for inlining the function instead of calling it (constexpr is inline by default but for other reasons...) but the compilers can ignore them.
Of course, the compiler can evaluate all constexpr functions with constexpr args at compile time, that is why they exist, why clang does not do so with -O0, I do not know.
If you need guaranteed compile-time evaluation, use consteval instead.
case1:
#include <string>
inline constexpr std::string test(std::string s) noexcept
{
return s + "xxx";
}
int main()
{
auto s = test("abc");
}
c++20 with gcc 12.1 is built okay, c++17 with gcc 12.1 or c++20/17 with gcc 11.1 was failed,
constexpr std::string, Is this a new feature, or what does this mean?
case2:
#include <string>
int main()
{
constexpr std::string test{"xxxxxx"};
}
And in this case both failed, what is the difference between these two cases.
There are two different use cases of constexpr here:
constexpr functions
constexpr objects
When you see it on a function such as
inline constexpr std::string test(std::string s) noexcept
{
return s + "xxx";
}
the constexpr is not part of the return type, in the same way that inline is not part of the return type; it is part of the function definition. In this case, constexpr says "this function can possibly be run at compile time".
The second use case you've mentioned is tagging an object definition as constexpr. In this use case, you're telling the compiler that this must be a compile time constant, and currently std::string objects cannot be marked constexpr due to the dynamic memory allocation that it does which it performed at runtime.
One thing you may have seen is that the std::string constructor was marked constexpr in C++20. This does not mean that you can create constexpr instances of std::string. It just means that std::string can be constructed and used within constexpr contexts (like a constexpr function).
You may then ask "if std::string requires runtime allocation, how can it be used within a constexpr function?". The basic answer is that the compiler uses a different allocation strategy to enable it, and does extra magic to make sure no undefined behaviour occurs. You can see more info here.
To give a bit more information about constexpr functions, note that I said it could "possibly" be run at compile time. A function marked constexpr can be run at either compile time or runtime, depending on the arguments it's called with
constexpr int double_val(int x) { return 2 * x; }
int main() {
const int y = double_val(4); // likely ran at compile time
int input = 0;
std::cin >> input;
const int z = double_val(input); // run at runtime
}
If you want to force the function to only run at compile time, that's what C++20's consteval keyword allows you to do.
consteval int double_val(int x) { return 2 * x; }
int main() {
const int y = double_val(4); // fine, ran at compile time
int input = 0;
std::cin >> input;
const int z = double_val(input); // ERROR, could not compile
}
The following might not compile either, for you:
constexpr auto s = test("abc");
There's a slight semantical difference between a constexpr object and a constexpr function.
A constexpr object must be a compile-time constant.
A constexpr function might be a compile-time constant if everything in the function is a constant expression. Subsequently, the result of the function is a constant expression if its parameters are, and obviously not if they're not.
What appears to be happening is that your compiler hasn't yet implemented the constexpr version of the std::string constructor in C++20, but has implemented the constexpr + operator.
Hence the function gets compiled without a constant expression as its parameter, but since its result is not assigned to a constexpr object this is not immediately apparent.
But assigning the function's result to a constexpr reveals the ugly truth.
If I want to have a function that behaves the same as a macro, that is, compute the value at compile time, can I use a constexpr function?
For example, can I replace the Foo macro by the foo function and still have a compile time evaluated result in all of the following cases:
#define FOO(x) (x + 2)
constexpr int foo(int x) {
return x + 2;
}
void doSomething(int a) { ... }
int main() {
int res1 = foo(3);
doSomething(foo(4));
const int res2 = foo(5);
return 0;
}
With C++20, consteval might be your friend here:
consteval int foo(int x) {
return x + 2;
}
int main() {
constexpr int r = foo(2);
}
By themselves, constexpr functions are not required to be evaluated at compile time. However, you can force them to be evaluated by assigning the return value to a constexpr variable:
doSomething(foo(4)); // foo(4) not guaranteed to be evaluated at compile time
constexpr auto result = foo(4); // foo(4) _is_ guaranteed to be evaluated at compile time
doSomething(result):
Also, a note about your question on macros. A macro definition has nothing to do with compile time evaluation. It's more akin to an always inline function.
It's impossible to detect if something was evaluated at runtime or compile-time using only the C++ itself, so the as-if rule allows the compiler to do whatever it wants.
Nothing stops a compiler from performing the addition in your macro at runtime, and nothing stops it from calculating even a non-constexpr function at compile-time (as long as it doesn't perform any IO, etc). It all depends on optimization settings and the sanity of the compiler.
Normally, in unoptimized builds, constexpr functions are executed at runtime unless the return value is used in a context that requires a compile-time constant. This includes initializing a constexpr variable from it, and your const int res2 implicitly becomes constexpr because its initializer is constexpr, so foo(5) should be called at compile-time.
In optimized builds, you can expect the compiler to do as much as possible at compile-time. (A function doesn't even have constexpr, as long as the function body is visible in the current translation unit, or if link-time optimizations are enabled.)
I have a rather big Map object and I want to have a separate list that has the keys sorted. This will be used in many other source files of my poject.
The question is about how do I know when a decalaration/definition is a compile time job. Where should I look to find if this is the case? I mean how to tell?
In the following example, is the list in the source file a compile time job or it happens at runtime?
Also, is there a way that I make the sorting operation at compile time?
// global.h
extern QMap<int, QString> G_MAP;
extern QList<int> G_MAP_SKEYS_SORTED;
// global.cpp
QMap<int, QString> G_MAP = { /* some hand filled (static) data */ };
QList<int> G_MAP_SKEYS_SORTED = G_MAP.keys();
// main.cpp
int mian() {
// Somewhere I do the sort
std::sort(G_ListRegistersSorted.begin(), G_ListRegistersSorted.end());
}
An expression is evaluated at compiletime if the result is assigned to a constexpr variable, used in a static_assert or noexcept statement, or used as a template parameter. This is called a constexpr context.
For example:
// Function which can calculate the fibbonacci sequence at compiletime
constexpr int fib(int n) {
if(n == 0 || n == 1) return n;
return fib(n - 1) + fib(n - 2);
}
int main() {
// This one is calculated at compiletime
constexpr int fib10_at_compiletime = fib(10);
// This one is calculated at runtime
// (unless the compiler was really aggressive when doing optimizations)
int fib10_at_runtime = fib(10);
}
In order to call a function or something at compiletime, it needs to be marked constexpr.
What can you do at compiletime?
C++11:
Declare variables (but not modify them)
Call other constexpr functions
Call constexpr constructors (and default ones)
Use carrays and std::array
Use static_asserts and stuff
typedef and using declarations
C++14 additions:
You can also use lambdas now
You can modify variables inside a constexpr function
you can have constexpr member functions that change member variables
you can pass references (the non-const kind) to constexpr functions
C++20 additions: (C++20 is coming out in 2020)
You can allocate memory now
You can call virtual functions now
You can have try-catch blocks
Is std::sort constexpr?
In order to use a function in a constexpr context, it must be marked constexpr (which comes with a set of restrictions on what you can do in the function; these are discussed below). In C++11, std::sort isn’t constexpr because it breaks those restrictions (and it won’t be constexpr until C++20).
However, if you’re allowed to use C++14, you can write your own sorting function that works at compile time.
Full overview: https://en.cppreference.com/w/cpp/language/constexpr
Also, is there a way that I make the sorting operation at compile time?
Short answer: no.
Long answer.
No because std::sort() is constexpr only from C++20 (you tagged C++11), because a void function (std::sort()) can't be constexpr in C++11, because QMap and QList aren't constexpr classes (if I'm not wrong), because you haven't declared GMAP and other object involved as constexpr, etc.
But, supposing to have a MyMap class defined constexpr, a MyList class declared constexpr, a MySort() function defined constexpr, you could write something similar (starting from C++14 because in C++11 you can't write a so complex constexpr function)
constexpr MyList foo ()
{
MyMap mm { /* some values */ };
MyList ml { ml.keys() };
MySort(ml.begin(), ml.end());
return ml;
}
// ...
constexpr auto ml_final { foo() };
Observe that ml_final is declared constexpr.
This is necessary to impose (pre C++20) the compiler to initialize the value compile-time, if possible, or give a compilation error, if impossible.
The setup:
I have a function that uses SIMD intrinsics and would like to use it inside some constexpr functions.
For that, I need to make it constexpr. However, the SIMD intrinsics are not marked constexpr, and the constant evaluator of the compiler cannot handle them.
I tried replacing the SIMD intrinsics with a C++ constexpr implementation that does the same thing. The function became 3.5x slower at run-time, but I was able to use it at compile-time (yay?).
The problem:
How can I use this function inside constant expressions without slowing down my program at run-time?
Some ideas:
Adding support for constant evaluating all SIMD intrinsics to the compiler constant expression evaluator, for all compilers: probably the right solution, but an impossible titanic task.
More pragmatic solutions would be to either:
overload a function depending on whether it is being executed inside a constant expression (that is, provide a constexpr, and a non-constexpr version).
or, somehow branch inside a constexpr function between the constexpr and run-time implementation (that is, detect in a branch whether the function is being executed inside a constant expression).
Anyhow, I am open to any suggestion that solves my problem.
Hints:
#RMartinhoFernandes suggested in the Lounge to use __builtin_constant_p to detect whether the function arguments are all constant expressions, in which case the compiler would hopefully be at least attempting to evaluate the function at compile-time.
Failed attempts:
#Jarod42 made the straight forward suggestion of just using two independent functions. I would briefly like to point out why this cannot work because it is not trivial. This solution assumes that at the call-site it is known whether the function will be constexpr evaluated or not. But this is not the case. Consider a constexpr function calling mine, which version of my function should it pick? It must pick the constexpr one in order for it to compile, but that "outer" constexpr function could still be evaluated at run-time. In that case, it would use the "slow" compile-time implementation, and hence, this approach does not solve the problem.
I would do it like this
constexpr int doit(int input, bool inconst = false) {
return inconst ? doitconsty(input) : doitfast(input);
}
If the call to doit is inside of a constexpr function that can be called to perform something either at runtime or at compile time, just forward the flag
constexpr int f(int n, bool inconst = false) {
/* ... */
int importantInt = doit(n / 42, inconst);
/* ... */
return magicResult;
}
Any constexpr evaluation has something where it starts, if I'm not mistaken. Pass the inconst there
enum foo { bar = f(256, true) }
If you are in the runtime world, just call f like anything else
int main() { std::cout << "test-case: " << f(256); }
It should be noted that this does not work for operators, because you can't add the boolean parameter there. Instead, you could pass the value in some different way, if that's fine for you (for primitive values like int and bool, we could not overload the operator either).
template<typename T>
struct maybe_const_value {
T t;
bool isconst;
};
enum foo { bar = maybe_const_value{256, true} % magicTransform };
int main() { return maybe_const_value{265} % magicTransform; }
The operator function can then check input.isconst and use input.t as the actual value.