Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ constexpr - Value can be evaluated at compile time?

Tags:

c++

c++11

I was reading about constexpr here:

The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time.

When I first read this sentence, it made perfect sense to me. However, recently I've come across some code that completely threw me off. I've reconstructed a simple example below:

#include <iostream>

void MysteryFunction(int *p);

constexpr int PlusOne(int input) {
  return input + 1;
}

int main() {
  int i = 0;
  MysteryFunction(&i);
  std::cout << PlusOne(i) << std::endl;

  return 0;
}

Looking at this code, there is no way for me to say what the result of PlusOne(i) should be, however it actually compiles! (Of course linking will fail, but g++ -std=c++11 -c succeeds without error.)

What would be the correct interpretation of "possible to evaluate the value of the function at compile time"?

like image 457
Apollys supports Monica Avatar asked Sep 10 '18 18:09

Apollys supports Monica


People also ask

Are constexpr evaluated at compile time?

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.

Is a const evaluated at compile time C++?

constexpr specifies that the value of an object or a function can be evaluated at compile-time and the expression can be used in other constant expressions.

How does constexpr work in C++?

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.

When to use #define vs constexpr?

#define (also called a 'macro') is simply a text substitution that happens during preprocessor phase, before the actual compiler. And it is obviously not typed. constexpr on the other hand, happens during actual parsing. And it is indeed typed.


4 Answers

A constexpr function may be called within a constant expression, provided that the other requirements for the evaluation of the constant expression are met. It may also be called within an expression that is not a constant expression, in which case it behaves the same as if it had not been declared with constexpr. As the code in your question demonstrates, the result of calling a constexpr function is not automatically a constant expression.

like image 90
Brian Bi Avatar answered Sep 19 '22 08:09

Brian Bi


The quoted wording is a little misleading in a sense. If you just take PlusOne in isolation, and observe its logic, and assume that the inputs are known at compile-time, then the calculations therein can also be performed at compile-time. Slapping the constexpr keyword on it ensures that we maintain this lovely state and everything's fine.

But if the input isn't known at compile-time then it's still just a normal function and will be called at runtime.

So the constexpr is a property of the function ("possible to evaluate at compile time" for some input, not for all input) not of your function/input combination in this specific case (so not for this particular input either).

It's a bit like how a function could take a const int& but that doesn't mean the original object had to be const. Here, similarly, constexpr adds constraints onto the function, without adding constraints onto the function's input.

Admittedly it's all a giant, confusing, nebulous mess (C++! Yay!). Just remember, your code describes the meaning of a program! It's not a direct recipe for machine instructions at different phases of compilation.

(To really enforce this you'd have the integer be a template argument.)

like image 39
Lightness Races in Orbit Avatar answered Sep 18 '22 08:09

Lightness Races in Orbit


What would be the correct interpretation of "possible to evaluate the value of the function at compile time"?

If all the arguments to the function are evaluatable at compile time, then the return value of the function can be evaluated at compile time.

However, if the values of the arguments to the function are known only at run time, then the retun value of the function can only be evaluated at run time.

Hence, it possible to evaluate the value of the function at compile time but it is not a requirement.

like image 22
R Sahu Avatar answered Sep 19 '22 08:09

R Sahu


All the answers are correct, but I want to give one short example that I use to explain how ridiculously unintuitive constexpr is.

#include <cstdlib>
constexpr int fun(int i){
    if (i==42){
        return 47;
    } else {
        return rand();
    }
}

int main()
{ 
    int arr[fun(42)];
}

As a side note: some people find constexpr status unsatisfying so they proposed constexpr! keyword addition to the language.

like image 31
NoSenseEtAl Avatar answered Sep 22 '22 08:09

NoSenseEtAl