389

It seems to me that having a "function that always returns 5" is breaking or diluting the meaning of "calling a function". There must be a reason, or a need for this capability or it wouldn't be in C++11. Why is it there?

// preprocessor.
#define MEANING_OF_LIFE 42

// constants:
const int MeaningOfLife = 42;

// constexpr-function:
constexpr int MeaningOfLife () { return 42; }

It seems to me that if I wrote a function that return a literal value, and I came up to a code-review, someone would tell me, I should then, declare a constant value instead of writing return 5.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
Warren P
  • 65,725
  • 40
  • 181
  • 316
  • 29
    Can you do define a recursive function that returns a `constexpr` ? If so, I can see an usage. – ereOn Jan 20 '11 at 14:24
  • 29
    I believe that the question should state "why introduce a new keyword (!) if the compiler can deduce for itself whether a function can be evaluated in compile time or not". Having it "guaranteed by a keyword" sounds good, but I think I'd prefer to have it guaranteed whenever it's possible, without the need for a keyword. – Kos Jan 20 '11 at 15:25
  • 7
    @Kos : Somebody who is MORE conversant with C++ internals would probably prefer your question, but my question comes from a perspective of a person who has written C code before, but is not familiar with C++ 2011 keywords at all, nor C++ compiler implementation details. Being able to reason about compiler optimization and constant-expression-deduction is a subject for a more advanced-user question than this one. – Warren P Oct 29 '12 at 14:33
  • 14
    @Kos I was thinking along the same lines as you, and the answer I came up with was, without constexpr, how would you (easily) *know* that the compiler actually compile-time-evaluated the function for you? I suppose you could check the assembly output to see what it did, but it's easier to just tell the compiler that you require that optimization, and if for some reason it can't do that for you, it will give you a nice compile-error instead of silently failing to optimize where you expected it to optimize. – Jeremy Friesner Jan 02 '13 at 05:34
  • 4
    @Kos: You could say the same thing about `const`. In fact, _mandated intent_ is **useful**! Array dimensions are the canonical example. – Lightness Races in Orbit Jun 04 '13 at 12:21
  • May be this article from `boost/hana` library can enlight some `constexpr` issues where you can use `constexpr` and where you can't: https://www.boost.org/doc/libs/1_69_0/libs/hana/doc/html/index.html#tutorial-appendix-constexpr – Andry Feb 07 '19 at 08:36
  • @JeremyFriesner I think your comment is a bit misleading. For example, if you use constexpr function with runtime variable, it will not fail and will silently just act as an inline function. It will only fail if the constexpr symbol can never be evaluated in compile time (eg. when you use `new`). – Tomáš Zato Mar 14 '19 at 10:07
  • 1
    I agree with Kos' comment. I still do not get why this keyword is needed. The compilers already do different optimizations up to replacing calculations with results during compiletime, if possible. Even "inline" is just a suggestion as the compiler knows better when to inline and when not. So why is "constexpr" necessary? I would expect that the compiler can do this stuff much better than I – Anonymous Dec 20 '21 at 11:07

15 Answers15

350

Suppose it does something a little more complicated.

constexpr int MeaningOfLife ( int a, int b ) { return a * b; }

const int meaningOfLife = MeaningOfLife( 6, 7 );

Now you have something that can be evaluated down to a constant while maintaining good readability and allowing slightly more complex processing than just setting a constant to a number.

It basically provides a good aid to maintainability as it becomes more obvious what you are doing. Take max( a, b ) for example:

template< typename Type > constexpr Type max( Type a, Type b ) { return a < b ? b : a; }

Its a pretty simple choice there but it does mean that if you call max with constant values it is explicitly calculated at compile time and not at runtime.

Another good example would be a DegreesToRadians function. Everyone finds degrees easier to read than radians. While you may know that 180 degrees is 3.14159265 (Pi) in radians it is much clearer written as follows:

const float oneeighty = DegreesToRadians( 180.0f );

Lots of good info here:

http://en.cppreference.com/w/cpp/language/constexpr

Goz
  • 61,365
  • 24
  • 124
  • 204
  • 21
    Excellent point with it telling the compiler to try and calculate the value at compile time. I'm curious why const doesn't provide this functionality when specific optimizations are specified? Or does it? – TamusJRoyce Jan 20 '11 at 14:37
  • 12
    @Tamus: Often it will but its not obliged to. constexpr obliges the compiler and will spit out an error if it can't. – Goz Jan 20 '11 at 14:38
  • 22
    I see it now. Sin(0.5) is another. This replaces C macros neatly. – Warren P Jan 20 '11 at 21:19
  • 13
    I can see this as a new interview question: Explain the differences between the const and constexpr keyword. – Warren P Jan 20 '11 at 21:30
  • 3
    As a way of documenting this point for myself I wrote similar code as above and again with the function being "const" rather than "constexpr". As I am using Clang3.3, -pedantic-errors and -std=c++11 I expected the latter would not compile. It compiled and ran as in the "constexpr" case. Do you suppose this is a clang extension or has there been a tweak to the C++11 spec since this post was answered? – Arbalest Jul 24 '13 at 22:44
  • 2
    Follow-up: the following only works when the function is "constexpr" --> char myArray[meaningOfLife]; – Arbalest Jul 24 '13 at 22:59
  • 2
    @Goz I don't think constexpr obligates the compiler to do the function at compile time - I am pretty sure if you feed the constexpr function a non const value it will run it at runtime and not produce a compiler error. – Jerry Jeremiah May 07 '19 at 23:08
  • My basic question: Why cant the compiler figure itself out what can be calculated during compile and what not? The compiler is already doing optimizations – Anonymous Dec 20 '21 at 11:11
199

Introduction

constexpr was not introduced as a way to tell the implementation that something can be evaluated in a context which requires a constant-expression; conforming implementations has been able to prove this prior to C++11.

Something an implementation cannot prove is the intent of a certain piece of code:

  • What is it that the developer want to express with this entity?
  • Should we blindly allow code to be used in a constant-expression, just because it happens to work?

What would the world be without constexpr?

Let's say you are developing a library and realize that you want to be able to calculate the sum of every integer in the interval (0,N].

int f (int n) {
  return n > 0 ? n + f (n-1) : n;
}

The lack of intent

A compiler can easily prove that the above function is callable in a constant-expression if the argument passed is known during translation; but you have not declared this as an intent - it just happened to be the case.

Now someone else comes along, reads your function, does the same analysis as the compiler; "Oh, this function is usable in a constant-expression!", and writes the following piece of code.

T arr[f(10)]; // freakin' magic

The optimization

You, as an "awesome" library developer, decide that f should cache the result when being invoked; who would want to calculate the same set of values over and over?

int func (int n) { 
  static std::map<int, int> _cached;

  if (_cached.find (n) == _cached.end ()) 
    _cached[n] = n > 0 ? n + func (n-1) : n;

  return _cached[n];
}

The result

By introducing your silly optimization, you just broke every usage of your function that happened to be in a context where a constant-expression was required.

You never promised that the function was usable in a constant-expression, and without constexpr there would be no way of providing such promise.


So, why do we need constexpr?

The primary usage of constexpr is to declare intent.

If an entity isn't marked as constexpr - it was never intended to be used in a constant-expression; and even if it is, we rely on the compiler to diagnose such context (because it disregards our intent).

Chris Nolet
  • 8,714
  • 7
  • 67
  • 92
Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196
  • 32
    This is probably the correct answer, since recent changes in C++14 and C++17 allow a much wider range of the language to be used in `constexpr` expressions. In other words, pretty much _anything_ can be annotated `constexpr` (maybe one day it will simply just go away because of this?), and unless one has a criterion of when to use `constexpr` or not, pretty much all of the code will be written as such. – alecov Jul 29 '16 at 16:11
  • 6
    @alecov Definitly not everything... ```I/O```, ```syscall``` and ```dynamic memory allocation``` definitly cann't be marked as ```constexpr``` Besides, not everything **should** be ```constexpr```. – JiaHao Xu Oct 08 '18 at 07:52
  • 1
    @alecov Some functions are meant to be executed at runtime and is meaningless to do this at compile-time. – JiaHao Xu Oct 08 '18 at 07:53
  • 3
    I also like this answer the best. Compile time evaluation is a neat optimization, but what you really get from `constexpr` is a guarantee of some kind of behavior. Just like `const` does. – Tomáš Zato Mar 14 '19 at 10:09
  • 1
    What compiler allows this constexpr-less version of `int f (int n) { return n > 0 ? n + f (n-1) : n;} T arr[f(10)];` I can't get this to compile anywhere? – Jer Apr 15 '20 at 18:15
  • `new`, `delete`, and more features are allowed in `constexpr` context as of C++20 – Desmond Gold Oct 02 '21 at 12:52
  • 1
    @Jer You are taking the example out of context, the reason it doesn't compile anywhere is why we need `constexpr`: it is used to declare intent and tell the compiler what we want. – Filip Roséen - refp Oct 04 '22 at 07:57
  • @Milan In a world where `constexpr` did not exist, the function would have been usable in a constant-expression (because everything would), by then changing the function to something which "obviously" cannot be used in a constant-expression everything that previously used the original implementation would now break (if they are used in such context). With this said, this is why we need `constexpr` as a keyword; to tell the compiler what we want. – Filip Roséen - refp Oct 04 '22 at 07:58
  • 1
    Going through a lot of different resource pages to understand a) the concept of constexpr and b) the use cases. This is one of the best answers, understanding the latter. The argument of sharing the intent - which translates to a great aspect of writing clean C++ code - is one that makes 100% sense and which is not pointed out often, when it comes to the constexpr topic. Thank you! – Weana Jan 14 '23 at 18:26
  • @Jer see here: https://godbolt.org/z/o5s9WWavj. It is interpreted as a [VLA](https://en.wikipedia.org/wiki/Variable-length_array), enabled by the toolchain when you dont pass `-pedantic`. – Geezer Jul 19 '23 at 09:50
95

Take std::numeric_limits<T>::max(): for whatever reason, this is a method. constexpr would be beneficial here.

Another example: you want to declare a C-array (or a std::array) that is as big as another array. The way to do this at the moment is like so:

int x[10];
int y[sizeof x / sizeof x[0]];

But wouldn’t it be better to be able to write:

int y[size_of(x)];

Thanks to constexpr, you can:

template <typename T, size_t N>
constexpr size_t size_of(T (&)[N]) {
    return N;
}
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 1
    +1 for nice template usage, but it'd work exactly the same without constexpr, wouldn't it? – Kos Jan 20 '11 at 15:26
  • 23
    @Kos: No. It would return a runtime value. `constexpr` forces the complier to make the function return a compile-time value (if it can). – deft_code Jan 20 '11 at 16:00
  • 16
    @Kos: without the `constexpr` it cannot be used in an array size declaration, nor as a template argument, regardless of whether the result of the function call is a compile-time constant or not. These two are basically the only use-cases for `constexpr` but at least the template argument use-case is kind of important. – Konrad Rudolph Jan 20 '11 at 16:11
  • 2
    "for whatever reason, this is a method": The reason is that there are only compile time integers in C++03, but no other compile time types, so only a method can work for arbitrary types prior to C++11. – Sebastian Mach Aug 06 '12 at 10:38
  • @phresnel I don’t understand that. You could just as well have a static const. It wouldn’t be a compile-time constant, but so what? The function also doesn’t return a compile-time constant, after all. – Konrad Rudolph Aug 06 '12 at 12:00
  • @Konrad Rudolph: Oops, static consts where an undercaffeination oversight by me. I think this is more about consistency: Users of numeric_limits<> may be tempted to use the static members as compile time constants, which may work for static const integers, but inconsistently wouldn't work for floating points or any other types. Making it a method ensured consistent behaviour. Also, as member variables can't be declared `inline`, you would have to put those static constants into separate units of compilation, imposing potential performance and usability constraints. – Sebastian Mach Aug 06 '12 at 12:28
  • `template unsigned char (&arr(T (&a)[N]))[N] { throw 0; } int y[sizeof(arr(x))];` would also work, although it's uglier. – user541686 Dec 01 '12 at 09:09
  • Making numeric_limits::max() a member function allows it to be evaluated at runtime. This could be useful in cross-compiling situations for standard library writers where the host architecture can't conveniently express a floating-point literal of the required value for the target architecture in code, but a small floating-point calculation at runtime could yield the correct value. – Adam H. Peterson Jan 15 '13 at 21:18
  • @Adam You can also do that at compile time – consider NaN which is conventionally expressed as `0.0 / 0.0`. Maybe there are more complex calculations – although I wonder why their results couldn’t be hard-coded. In any case this is now moot with `constexpr`. – Konrad Rudolph Jan 15 '13 at 22:56
  • But `int a = 5; char tmp[a];` is OK now in my gcc-4.9.2:) – Lw Cui Aug 17 '16 at 11:12
  • 6
    @LwCui No, it’s not “ok”: GCC is just lax by default about certain things. Use the `-pedantic` option and it will be flagged as an error. – Konrad Rudolph Aug 17 '16 at 12:53
  • Just one question, most of the code examples given here will be within functions that are called at runtime. If the function itself is called at runtime, how can the `constexpr` code within that function be computed at compile time and save run time? – SexyBeast Oct 09 '16 at 15:38
  • 2
    @SexyBeast not sure what you mean? int size is know at compile time, the constant 10 is known at compile time, so the array size is also known at compile time, nothing is "called" at run time – paulm Nov 18 '16 at 11:56
20

constexpr functions are really nice and a great addition to c++. However, you are right in that most of the problems it solves can be inelegantly worked around with macros.

However, one of the uses of constexpr has no C++03 equivalent, typed constants.

// This is bad for obvious reasons.
#define ONE 1;

// This works most of the time but isn't fully typed.
enum { TWO = 2 };

// This doesn't compile
enum { pi = 3.1415f };

// This is a file local lvalue masquerading as a global
// rvalue.  It works most of the time.  But May subtly break
// with static initialization order issues, eg pi = 0 for some files.
static const float pi = 3.1415f;

// This is a true constant rvalue
constexpr float pi = 3.1415f;

// Haven't you always wanted to do this?
// constexpr std::string awesome = "oh yeah!!!";
// UPDATE: sadly std::string lacks a constexpr ctor

struct A
{
   static const int four = 4;
   static const int five = 5;
   constexpr int six = 6;
};

int main()
{
   &A::four; // linker error
   &A::six; // compiler error

   // EXTREMELY subtle linker error
   int i = rand()? A::four: A::five;
   // It not safe use static const class variables with the ternary operator!
}

//Adding this to any cpp file would fix the linker error.
//int A::four;
//int A::six;
deft_code
  • 57,255
  • 29
  • 141
  • 224
  • 1
    Does the standard really define std::string to have a constexpr constructor? (It at least doesn't work with GCC 4.6, which otherwise supports constexpr.) – wjl Jun 10 '11 at 17:41
  • 1
    no, most of std::strings constructors _cannot_ be constexrp, they need the runtime heap. – Mooing Duck Jan 05 '12 at 15:43
  • @MooingDuck, unfortunately you're correct. `std::string` will not receive a `constexpr` ctor. It definitely could be done, it could probably be done cheaply. But I don't know if it could be done cheaply enough for the standard library (don't pay for what you don't use). – deft_code Feb 27 '12 at 17:03
  • 1
    @deft_code: The more I think about it, the more I think it shouldn't be done. (1) allow `constexpr` string from `const char (&)[N]` (lots of potential UB, requires string to be bigger). (2) greatly increase SBO size (strings _much bigger, fails for long strings) (3) Make a custom string type (already have it: string literal). – Mooing Duck Feb 27 '12 at 17:14
  • @MooingDuck, I mostly agree. It would be tough to provide a zero cost constexpr ctor. The newly proposed `std::string_ref` might be a much better candidate for a `constexpr` ctor. – deft_code Feb 28 '12 at 15:18
  • 2
    @MooingDuck: A string object has the size included which is nice. Also, using a string literal aka a char array requires copying the whole thing every time its passed into a function that takes a std::string. I see definite advantages to some kind to std::string compatible constexpr object. – Zan Lynx Feb 13 '13 at 23:19
  • @ZanLynx: string literals have the size included, and any non-`std::string` type would have to be copied. What exactly do you mean by `std::string` compatible? If you mean `std::string` itself, can't be done. If you mean a type with the same interface as `std::string`, I see no point, since we have string literals, and if you mean something with a different interface that converts to a `std::string`, we have string literals. Yes, there's lots of irritants with it, but C++ won't be able to do much better. – Mooing Duck Feb 13 '13 at 23:30
  • 1
    @MooingDuck A string literal may have its size included, when written as a literal. But if you pass it to a function, that information is discarded and it gets treated as a simple `const char *`. Here's a good example: http://liveworkspace.org/code/4b1wqc$11 – Agentlien Feb 15 '13 at 13:30
  • 1
    I am a big fan of the proposed [`std::string_ref`](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html). Basically it provides a simple abstraction for immutable strings. Since it can't be changed it could be a `std::string`, c-string literal, or anything else. I easily avoids the whole argument of the advantages of `std::string` vs c-string literal. – deft_code Feb 15 '13 at 17:06
  • 1
    @Agentlien: You passed by value, and arrays won't pass by value. If you pass by reference like a sane person, you can see that the size information remains. Example: http://liveworkspace.org/code/4b1wqc$13 – Mooing Duck Feb 15 '13 at 17:38
  • 1
    @MooingDuck You're right, I accidentally passed by value. I can see that passing by reference actually does keep the information about array size. I didn't realize that worked, very handy. Too bad it only works for templated functions, though. – Agentlien Feb 15 '13 at 20:43
  • 13
    Could you please clarify that "EXTREMELY subtle linker error"? Or at least provide a pointer to a clarification? – enobayram Jul 24 '13 at 14:34
  • 4
    @enobayram, The ternary operator takes the address of the operands. That is not obvious from the code. Everything compiles fine, but the link fails because the address of `four` doesn't resolve. I had to really dig to figure who was taking the address of my `static const` variable. – deft_code Jul 24 '13 at 19:48
  • @deft_code Thanks a lot for the clarification, you've got a good point, but I wouldn't call it "unsafe" since you don't risk anything, you just get an annoying linker error. You're right that the error does not point to where the addresses are taken, but it's easy to solve simply by defining `const int A::four;` in the global scope. – enobayram Jul 26 '13 at 15:44
  • 26
    "This is bad for obvious reasons": the most obvious reason being the semicolon, right? – TonyK Jul 28 '13 at 20:50
  • 4
    The "EXTREMELY subtle linker error" has me completely puzzled. Neither `four` nor `five` are in scope. – Steven Lu Aug 30 '13 at 23:30
  • 3
    see also the new `enum class` type, it fixes some of the enum issues. – ninMonkey Sep 05 '13 at 02:53
  • Possibly [this bug](http://bobobobo.wordpress.com/2013/06/01/extern-variable-always-0/) which has got me before. Unfortunately `constexpr` can't be used to solve the problem linked, because the compiler says you can't use a `constexpr` for a non-literal type, which apparently my `Vector4f` class is. – bobobobo Dec 16 '13 at 13:52
  • Fun aside, in Visual Studio 2013 the ternary operator works, it appears that assigning a value to "four" or "five" is doing the variable instantiation and there is no linker error. – Lambage Apr 29 '16 at 13:14
  • 1
    This answer doesn't explain anything - it just throws some hints around. Also, when explicitly asked to clarify, the author didn't do so (for several unclear points). Also, there is commented-out code that doesn't work and it's not clear whether it's relevant. – anatolyg Oct 17 '16 at 16:55
15

From what I've read, the need for constexpr comes from an issue in metaprogramming. Trait classes may have constants represented as functions, think: numeric_limits::max(). With constexpr, those types of functions can be used in metaprogramming, or as array bounds, etc etc.

Another example off of the top of my head would be that for class interfaces, you may want derived types define their own constants for some operation.

Edit:

After poking around on SO, it looks like others have come up with some examples of what might be possible with constexprs.

Community
  • 1
  • 1
luke
  • 36,103
  • 8
  • 58
  • 81
  • "To be part of an interface you've got to be a function"? – Daniel Earwicker Jan 20 '11 at 14:24
  • Now that I can see the usefulness of this, I'm a little more excited about C++ 0x. It seems a well thought out thing. I knew they must be. Those language standard uber-geeks seldom do random things. – Warren P Jan 20 '11 at 21:24
  • I'm way more excited about lambdas, the threading model, initializer_list, rvalue references, variadic templates, the new bind overloads... there's quite a bit to look forward to. – luke Jan 20 '11 at 23:29
  • 1
    Oh yeah, but I already understand lambdas/closures in several other languges. `constexpr` is more specifically useful in a compiler with a powerful compile-time expression evaluation system. C++ really has no peers in that domain. (that's a strong praise for C++11, IMHO) – Warren P Nov 10 '11 at 16:17
11

From Stroustrup's speech at "Going Native 2012":

template<int M, int K, int S> struct Unit { // a unit in the MKS system
       enum { m=M, kg=K, s=S };
};

template<typename Unit> // a magnitude with a unit 
struct Value {
       double val;   // the magnitude 
       explicit Value(double d) : val(d) {} // construct a Value from a double 
};

using Speed = Value<Unit<1,0,-1>>;  // meters/second type
using Acceleration = Value<Unit<1,0,-2>>;  // meters/second/second type
using Second = Unit<0,0,1>;  // unit: sec
using Second2 = Unit<0,0,2>; // unit: second*second 

constexpr Value<Second> operator"" s(long double d)
   // a f-p literal suffixed by ‘s’
{
  return Value<Second> (d);  
}   

constexpr Value<Second2> operator"" s2(long double d)
  // a f-p literal  suffixed by ‘s2’ 
{
  return Value<Second2> (d); 
}

Speed sp1 = 100m/9.8s; // very fast for a human 
Speed sp2 = 100m/9.8s2; // error (m/s2 is acceleration)  
Speed sp3 = 100/9.8s; // error (speed is m/s and 100 has no unit) 
Acceleration acc = sp1/0.5s; // too fast for a human
  • 2
    This example can also be found in Stroustrup's paper [Software Development for Infrastructure](http://www.stroustrup.com/Software-for-infrastructure.pdf). – Matthieu Poullet Jul 24 '13 at 07:29
  • clang-3.3: error: constexpr function's return type 'Value' is not a literal type – Mitja Aug 26 '13 at 06:23
  • This is nice but who puts literals in code like this. Having your compiler "check your units" for you would make sense if you were writing an interactive calculator. – bobobobo Dec 16 '13 at 04:02
  • 7
    @bobobobo or if you were writing navigation software for the Mars Climate Orbiter, maybe :) – Jeremy Friesner Jan 18 '16 at 03:40
  • 1
    To make it compile - 1. Use underscore in the literal suffixes. 2. add operator ""_m for 100_m. 3. use 100.0_m, or add an overload that accepts unsigned long long. 4. Declare the Value constructor constexpr. 5. Add corresponding operator / to the Value class like this: constexpr auto operator / (const Value& other) const { return Value::TheUnit::m, TheUnit::kg - Value::TheUnit::kg, TheUnit::s - Value::TheUnit::s>>(val / other.val); }. Where TheUnit is typedef for Unit added inside of the Value class. – 0kcats Dec 09 '16 at 18:44
9

Another use (not yet mentioned) is constexpr constructors. This allows creating compile time constants which don't have to be initialized during runtime.

const std::complex<double> meaning_of_imagination(0, 42); 

Pair that with user defined literals and you have full support for literal user defined classes.

3.14D + 42_i;
Motti
  • 110,860
  • 49
  • 189
  • 262
8

Have just started switching over a project to c++11 and came across a perfectly good situation for constexpr which cleans up alternative methods of performing the same operation. The key point here is that you can only place the function into the array size declaration when it is declared constexpr. There are a number of situations where I can see this being very useful moving forward with the area of code that I am involved in.

constexpr size_t GetMaxIPV4StringLength()
{
    return ( sizeof( "255.255.255.255" ) );
}

void SomeIPFunction()
{
    char szIPAddress[ GetMaxIPV4StringLength() ];
    SomeIPGetFunction( szIPAddress );
}
jgibbs
  • 430
  • 5
  • 13
7

There used to be a pattern with metaprogramming:

template<unsigned T>
struct Fact {
    enum Enum {
        VALUE = Fact<T-1>*T;
    };
};

template<>
struct Fact<1u> {
    enum Enum {
        VALUE = 1;
    };
};

// Fact<10>::VALUE is known be a compile-time constant

I believe constexpr was introduced to let you write such constructs without the need for templates and weird constructs with specialization, SFINAE and stuff - but exactly like you'd write a run-time function, but with the guarantee that the result will be determined in compile-time.

However, note that:

int fact(unsigned n) {
    if (n==1) return 1;
    return fact(n-1)*n;
}

int main() {
    return fact(10);
}

Compile this with g++ -O3 and you'll see that fact(10) is indeed evaulated at compile-time!

An VLA-aware compiler (so a C compiler in C99 mode or C++ compiler with C99 extensions) may even allow you to do:

int main() {
    int tab[fact(10)];
    int tab2[std::max(20,30)];
}

But that it's non-standard C++ at the moment - constexpr looks like a way to combat this (even without VLA, in the above case). And there's still the problem of the need to have "formal" constant expressions as template arguments.

Kos
  • 70,399
  • 25
  • 169
  • 233
  • The fact function is not evaluated at compile-time. It needs to be constexpr and must have only one return statement. – Sumant Jul 19 '11 at 17:08
  • 1
    @Sumant: You are right that it doesn't have to be evaluated at compile-time, but it is! I was referring to what really happens in compilers. Compile it on recent GCC, see resulting asm and check for yourself if you don't believe me! – Kos Jul 19 '11 at 18:50
  • Try to add `std::array` and you'll see that fact() is not evaluated at compile-time. It's just the GCC optimizer doing a good job. –  Feb 15 '12 at 14:12
  • 2
    That's what I said... am I really that unclear? See the last paragraph – Kos Feb 15 '12 at 18:46
4

All of the other answers are great, I just want to give a cool example of one thing you can do with constexpr that is amazing. See-Phit (https://github.com/rep-movsd/see-phit/blob/master/seephit.h) is a compile time HTML parser and template engine. This means you can put HTML in and get out a tree that is able to be manipulated. Having the parsing done at compile time can give you a bit of extra performance.

From the github page example:

#include <iostream>
#include "seephit.h"
using namespace std;



int main()
{
  constexpr auto parser =
    R"*(
    <span >
    <p  color="red" height='10' >{{name}} is a {{profession}} in {{city}}</p  >
    </span>
    )*"_html;

  spt::tree spt_tree(parser);

  spt::template_dict dct;
  dct["name"] = "Mary";
  dct["profession"] = "doctor";
  dct["city"] = "London";

  spt_tree.root.render(cerr, dct);
  cerr << endl;

  dct["city"] = "New York";
  dct["name"] = "John";
  dct["profession"] = "janitor";

  spt_tree.root.render(cerr, dct);
  cerr << endl;
}
Halcyon
  • 1,376
  • 1
  • 15
  • 22
2

A lot of the responses here seem to have things a bit backwards, and/or are saying the quiet part loud and the loud part quiet. The one key thing to know about constexpr is this:

// This guarantees only that the value of "MeaningOfLife" can not be changed
// from the value calculated on this line by "complex_initialization()"
// (unless you cast away the const of course, don't do that).
// Critically here, everything happens at *runtime*.
const int MeaningOfLife = complex_initialization(1234, 5678, "hello");
// This guarantees that "MeaningOfLife" is fully evaluated and "initialized"
// *at compile time*.  If that is not possible due to complex_initialization()
// not being evaluatable at compile time, the compiler is required to abort
// compilation of the program.
// Critically here, to put a fine point on it, everything happens at
// *compile time*, guaranteed.  There won't be a runtime call to
// complex_initialization() at all in the final program.
constexpr int MeaningOfLife = complex_initialization(1234, 5678, "hello");

Note that it's the constexpr-ness of the left-hand side which forces the guarantees which give constexpr its reason to exist. It is up to you to make sure the right-hand side can in fact be evaluated at compile time of course, and importantly, just declaring a function constexpr does not in and of itself do that.

So the answer to your question is that you should declare a variable constexpr when you need or want its initialization (everything happening on the right-hand side) to be forced to either happen entirely at compile time or break the build.

1

Your basic example serves he same argument as that of constants themselves. Why use

static const int x = 5;
int arr[x];

over

int arr[5];

Because it's way more maintainable. Using constexpr is much, much faster to write and read than existing metaprogramming techniques.

Puppy
  • 144,682
  • 38
  • 256
  • 465
0

It can enable some new optimisations. const traditionally is a hint for the type system, and cannot be used for optimisation (e.g. a const member function can const_cast and modify the object anyway, legally, so const cannot be trusted for optimisation).

constexpr means the expression really is constant, provided the inputs to the function are const. Consider:

class MyInterface {
public:
    int GetNumber() const = 0;
};

If this is exposed in some other module, the compiler can't trust that GetNumber() won't return different values each time it's called - even consecutively with no non-const calls in between - because const could have been cast away in the implementation. (Obviously any programmer who did this ought to be shot, but the language permits it, therefore the compiler must abide by the rules.)

Adding constexpr:

class MyInterface {
public:
    constexpr int GetNumber() const = 0;
};

The compiler can now apply an optimisation where the return value of GetNumber() is cached and eliminate additional calls to GetNumber(), because constexpr is a stronger guarantee that the return value won't change.

AshleysBrain
  • 22,335
  • 15
  • 88
  • 124
  • Actually `const` **can** be used in optimisation... It's undefined behaviour to modify a value *defined const* even after a `const_cast` IIRC. I'd expect it to be consistent for `const` member functions, but I'd need to check that with the standard. This would mean that the compiler can safely do optimisations there. – Kos Jan 20 '11 at 23:27
  • 1
    @Warren: it doesn't matter if the optimization is actually done, it's just allowed. @Kos: it's a little-known subtlety that if the *original* object was *not* declared const (`int x` vs. `const int x`), then it is safe to modify it by `const_cast` -ing away const on a pointer/reference to it. Otherwise, `const_cast` would always invoke undefined behavior, and be useless :) In this case, the compiler has no information about the const-ness of the original object, so it can't tell. – AshleysBrain Jan 21 '11 at 01:59
  • @Kos I don't think const_cast is the only issue here. The const method is allowed to read and even modify a global variable. Conversely, someone from anpther thread could also modify the const object between the calls. – enobayram Jul 24 '13 at 14:47
  • 2
    The "= 0" isn't valid here and should be removed. I'd do it myself, but I'm not sure that's in conformance with SO protocol. – KnowItAllWannabe Jan 24 '14 at 03:15
  • 1
    Both examples are invalid: the first one (`int GetNumber() const = 0;`) should declare the `GetNumber()` method virtual. The second (`constexpr int GetNumber() const = 0;`) isn't valid because the pure specifier (`= 0`) implies the method to be virtual, but constexpr's must not be virtual (ref: http://en.cppreference.com/w/cpp/language/constexpr) – stj Mar 04 '16 at 10:22
-4

It's useful for something like

// constants:
const int MeaningOfLife = 42;

// constexpr-function:
constexpr int MeaningOfLife () { return 42; }

int some_arr[MeaningOfLife()];

Tie this in with a traits class or the like and it becomes quite useful.

lakshayg
  • 2,053
  • 2
  • 20
  • 34
plivesey
  • 59
  • 1
  • 4
    In your example it offers zero advantage over a plain constant, so it doesn't really answer the question. – jalf Jan 20 '11 at 14:48
  • This is a contrived example, imagine if MeaningOfLife() gets its value from somewhere else, say another function or a #define or series therof. You may not know what it returns, it may be library code. Other examples, imagine an immutable container that has a constexpr size() method. You can now do int arr[container.size()]; – plivesey Jan 21 '11 at 11:49
  • 2
    @plivesey can you please edit your answer with a better example then. – Mukesh Sep 20 '17 at 06:14
-4

When to use constexpr:

  1. whenever there is a compile time constant.
BreakBadSP
  • 820
  • 10
  • 21
  • While I agree with you, this answer doesn't explain *why* `constexpr` should be preferred over preprocessor macros or `const`. – Sneftel Jun 13 '19 at 12:31