9

If an object is declared const, its value is guaranteed to be available only at runtime, but if it's declared constexpr, the value is guaranteed to be available both during compilation and at runtime. So if I have an object whose value is available during compilation, are there any situations where I should not declare it constexpr?

const int magicValue = 42; // Does this ever make sense // (using const instead of constexpr)? 

For functions, if a function can return a value computed during compilation when passed arguments with values available during compilation, would it ever make sense to not declare the function constexpr?

struct Point { int x; int y; }; Point midPoint(Point p1, Point p2) // Does this ever make { // sense (not declaring return { (p1.x + p2.x) / 2 , (p1.y + p2.y) / 2 }; // the function } // constexpr)? 

The only case I can conceive of is when you don't want to commit to the function being able to compute a compile-time constant when called with known-at-compile-time arguments, e.g., if you want to preserve the flexibility to change midPoint's implementation without changing its interface (thus potentially breaking callers). For example, you might want to preserve the flexibility to add non-constexpr side-effects to midPoint, e.g., IO.

3
  • 2
    In code that has to compile under previous iterations of the standard? For example, library code that you want to be able to compile with a C++03 compiler. Commented Jan 3, 2014 at 4:38
  • 1
    Fair enough, but I'm really interested in cases where it would compile either way. Commented Jan 3, 2014 at 4:40
  • 3
    @stefan Why can you not benchmark a constexpr function? If the arguments are supplied at run-time, it will be computed at run-time. If the arguments are known at compile-time, even a non-constexpr function might be computed at compile-time. It's nothing to do with whether the function is marked as constexpr. Commented Jan 3, 2014 at 10:52

2 Answers 2

4

For variables, I don't see any reason not to use constexpr when you can. But it's not always possible to do so, e.g. when the initializer of a variable is computed by a virtual function e.g.

Adding constexpr to a function is an interface change: you are expressing the fact that you can use it to initialize constexpr variables. This imposes constraints on the implementation of your function, such as no calling of virtual functions, no dynamic memory allocations and no lambda functions as function objects.

Note that the resolution to LWG issue 2013 does not allow implementers of the Standard Library the freedom to add constexpr to library functions. One of the reasons is that declaring a function constexpr can inhibit certain debugging implementations that do dynamic allocations (notably iterator checking). This means that future expansions of constexpr to the Standard Library need to be separate proposals. This is in contrast to noexcept, where library writers have more freedom.

Sign up to request clarification or add additional context in comments.

1 Comment

Adding constexpr to a function is an interface change: Thank you for this helpful note. Is there an official list of what counts as interface changes?
0

You can change a const:

int const x = 1; *const_cast<int *>(&x) = 5; 

You cannot do the same with constexpr, which allows the compiler to know without a doubt that the expression is available at compile time, and thus optimizations are possible.

2 Comments

Well if you don't mind the nasal demons... Modifying an object declared as const invokes Undefined Behaviour.
Actually, modifying an object defined as const invokes UB. (It's not enough for it to be merely declared const.)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.