458

Is there a difference between the following definitions?

const     double PI = 3.141592653589793;
constexpr double PI = 3.141592653589793;

If not, which style is preferred in C++11?

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • 3
    Superset: http://stackoverflow.com/questions/14116003/difference-between-constexpr-and-const – Ciro Santilli OurBigBook.com Oct 15 '15 at 13:02
  • Both are compile-time constant. But you can do a const_cast of the first and write to it. But it will be optimized away by any compiler since this doesn't influence "reads" as they happen at compile-time. – Bonita Montero Dec 07 '19 at 10:08
  • Does this answer your question? [What's the difference between constexpr and const?](https://stackoverflow.com/questions/14116003/whats-the-difference-between-constexpr-and-const) – Donald Duck Oct 14 '22 at 12:21

6 Answers6

520

I believe there is a difference. Let's rename them so that we can talk about them more easily:

const     double PI1 = 3.141592653589793;
constexpr double PI2 = 3.141592653589793;

Both PI1 and PI2 are constant, meaning you can not modify them. However only PI2 is a compile-time constant. It shall be initialized at compile time. PI1 may be initialized at compile time or run time. Furthermore, only PI2 can be used in a context that requires a compile-time constant. For example:

constexpr double PI3 = PI1;  // error

but:

constexpr double PI3 = PI2;  // ok

and:

static_assert(PI1 == 3.141592653589793, "");  // error

but:

static_assert(PI2 == 3.141592653589793, "");  // ok

As to which you should use? Use whichever meets your needs. Do you want to ensure that you have a compile time constant that can be used in contexts where a compile-time constant is required? Do you want to be able to initialize it with a computation done at run time? Etc.

Deqing
  • 14,098
  • 15
  • 84
  • 131
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 93
    Are you sure? Because `const int N = 10; char a[N];` works, and array bounds must be compile-time constants. – fredoverflow Nov 12 '12 at 16:22
  • 13
    I am sure as far as the examples I wrote go (tested each of them before posting). However my compiler does let me convert `PI1` to a compile-time integral constant for use in an array, but not for use as a non-type integral template parameter. So the compile-time convertibility of `PI1` to an integral type seems a little hit & miss to me. – Howard Hinnant Nov 12 '12 at 16:26
  • @HowardHinnant: The rules for lvalue-to-rvalue conversion are subtly different for integral and non-integral types: (5.19(2)) `a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression` vs. `a glvalue of literal type that refers to a non-volatile object defined with constexpr, or that refers to a sub-object of such an object`. That's not the same as implicit conversion to `int`, which has different rules. – rici Nov 12 '12 at 16:49
  • 46
    @FredOverflow: Non-const array indices have "worked" for about a decade (there's for example a g++ extension for that), but that does not mean it's strictly legal C++ (though some more recent C or C++ standard _made it legal_, I forgot which one). As for differences in compiletime constants, template parameters and use as `enum` initializer are the only two notable differences between `const` and `constexpr` (and neither works for `double` anyway). – Damon Nov 12 '12 at 16:53
  • 1
    @Damon: They do not work in Clang though. However `size_t const int N = 10; char a[N];` works in C++, but not in C (where you need to `#define N 10`). – Matthieu M. Nov 12 '12 at 17:57
  • 22
    Paragraph 4 of 5.19 Constant expressions [expr.const] is also a (non-normative) note that famously outlines that an implementation is allowed to do floating-point arithmetic differently (e.g. with respect to accuracy) at compile-time than at runtime. So `1 / PI1` and `1 / PI2` may yield different results. I don't think this technicality is quite as important as the advice in this answer however. – Luc Danton Nov 12 '12 at 19:07
  • 6
    But it `constexpr double PI3 = PI1;` works correctly for me. (MSVS2013 CTP). What am I doing wrong? – NuPagadi Mar 10 '14 at 15:32
  • 3
    @user2198121: You're not doing anything wrong. Just know that you're taking advantage of a compiler extension. The code is safe, but not portable. On porting any difference will be found at compile-time, not run-time. – Howard Hinnant Mar 10 '14 at 21:32
  • 1
    Will `PI2` have a runtime memory address? If so, I wonder why, since in theory all constant expressions should be inlined (no need to keep a variable around); especially if this is all done by the compiler. The final object code should not have any knowledge of that variable. – void.pointer Oct 01 '14 at 23:49
  • 2
    `PI2` will have internal linkage, meaning it will be local to a translation unit. It will theoretically have an address. However if that address is never used, it need not exist. If `PI2` is ever passed by reference, the compiler will need to store it somewhere for the reference to refer to (unless that function is inlined and the compiler is able to optimize away the reference). – Howard Hinnant Oct 02 '14 at 02:56
  • 1
    A note for anyone confused by `constexpr double PI3 = PI1; // error` - The error is compiler specific. For instance, some compilers will go ahead see that `PI1` itself is a literal, and therefore resolve that that is legal. Others, due to the nature of `const`, won't perform this check because it may or may not be a literal. – Super Cat May 27 '15 at 03:56
  • @HowardHinnant i don't get any errors on constexpr double PI3 = PI1; Any idea? – yapkm01 Sep 08 '15 at 19:58
  • 1
    Thank you for your helpful answer! Had a problem with static_assert, now it's all clear to me. I wonder why it's typed with mistake in Straustup book...(C++ 4th edition) –  Feb 12 '16 at 16:34
  • I could be wrong, but can't the compiler choose to make a variable a constexpr on its own in certain contexts? So, for example, when you have a const literal like that, it can probably decide it is safe to make it a constexpr, therefore allowing you to use it for array size, static_assert, `constexpr PI3 = PI1;`, template parameters, etc... – Shelby Oldfield Sep 05 '17 at 21:13
  • 1
    it may be obvious: but what about taking references from these PIs (pun intended)? should be possible from `PI1` impossible from `PI2` – Florian Feb 23 '19 at 20:38
  • @Damon "_but that does not mean it's strictly legal C++_" No, actually `const int k = 1;` has always been a compile time constant in C++. "_(there's for example a g++ extension for that),_" Although there are extensions re: variable size arrays. – curiousguy Oct 12 '19 at 12:11
  • @Florian Passing a constexpr to a const reference is OK. As you would expect, taking the address of a constexpr to pass to a pointer will not compile. – David Bradley Jan 28 '23 at 23:23
104

No difference here, but it matters when you have a type that has a constructor.

struct S {
    constexpr S(int);
};

const S s0(0);
constexpr S s1(1);

s0 is a constant, but it does not promise to be initialized at compile-time. s1 is marked constexpr, so it is a constant and, because S's constructor is also marked constexpr, it will be initialized at compile-time.

Mostly this matters when initialization at runtime would be time-consuming and you want to push that work off onto the compiler, where it's also time-consuming, but doesn't slow down execution time of the compiled program

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • 5
    I agree: the conclusion I arrived to was that `constexpr` would lead to a diagnosis should the compile-time computation of the object be impossible. What is less clear is whether a function *expecting* a constant parameter could be executed at compile-time should the parameter be declared as `const` and not as `constexpr`: ie, would `constexpr int foo(S)` be executed at compile-time if I call `foo(s0)` ? – Matthieu M. Nov 12 '12 at 16:07
  • 7
    @MatthieuM: I doubt whether `foo(s0)` would be executed at compile-time, but you never know: a compiler is allowed to do such optimizations. Certainly, neither gcc 4.7.2 nor clang 3.2 allow me to compile `constexpr a = foo(s0);` – rici Nov 12 '12 at 17:16
74

constexpr indicates a value that's constant and known during compilation.
const indicates a value that's only constant; it's not compulsory to know during compilation.

int sz;
constexpr auto arraySize1 = sz;    // error! sz's value unknown at compilation
std::array<int, sz> data1;         // error! same problem

constexpr auto arraySize2 = 10;    // fine, 10 is a compile-time constant
std::array<int, arraySize2> data2; // fine, arraySize2 is constexpr

Note that const doesn’t offer the same guarantee as constexpr, because const objects need not be initialized with values known during compilation.

int sz;
const auto arraySize = sz;       // fine, arraySize is const copy of sz
std::array<int, arraySize> data; // error! arraySize's value unknown at compilation

All constexpr objects are const, but not all const objects are constexpr.

If you want compilers to guarantee that a variable has a value that can be used in contexts requiring compile-time constants, the tool to reach for is constexpr, not const.

visitor
  • 672
  • 6
  • 17
Ajay yadav
  • 4,141
  • 4
  • 31
  • 40
  • 3
    I liked your explanation a lot..can you please comment more on Where are the cases we may need to use compile time constants in real life scenarios. – Mayukh Sarkar Aug 01 '16 at 09:07
  • 1
    @MayukhSarkar Simply Google _C++ why constexpr_, e.g. http://stackoverflow.com/questions/4748083/when-should-you-use-constexpr-capability-in-c11 – underscore_d Aug 13 '16 at 19:27
27

A constexpr symbolic constant must be given a value that is known at compile time. For example:

constexpr int max = 100; 
void use(int n)
{
    constexpr int c1 = max+7; // OK: c1 is 107
    constexpr int c2 = n+7;   // Error: we don’t know the value of c2
    // ...
}

To handle cases where the value of a “variable” that is initialized with a value that is not known at compile time but never changes after initialization, C++ offers a second form of constant (a const). For Example:

constexpr int max = 100; 
void use(int n)
{
    constexpr int c1 = max+7; // OK: c1 is 107
    const int c2 = n+7; // OK, but don’t try to change the value of c2
    // ...
    c2 = 7; // error: c2 is a const
}

Such “const variables” are very common for two reasons:

  1. C++98 did not have constexpr, so people used const.
  2. List item “Variables” that are not constant expressions (their value is not known at compile time) but do not change values after initialization are in themselves widely useful.

Reference : "Programming: Principles and Practice Using C++" by Stroustrup

codeling
  • 11,056
  • 4
  • 42
  • 71
Jnana
  • 824
  • 13
  • 12
  • 39
    Perhaps you should have mentioned that the text in your answer is taken verbatim from "Programming: Principles and Practice Using C++" by Stroustrup – Aky May 16 '16 at 21:14
5

One more example to understand the difference between const and constexp.

int main()
{
    int n;
    cin >> n;               

    const int c = n;        // OK: 'c' can also be initialized at run time
    constexpr int e = n;    // Error: 'e' must be initialized at compile time
}

Note: constexpr normally evaluated at compile-time, but they are not guaranteed to do so unless they're invoked in a context where a constant expression is required.

constexpr int add(int a, int b)
{
    return a + b;
};


int main()
{
    int n = add(4, 3);          // may or may not be computed at compile time
    constexpr int m = add(4,3); // must be computed at compile time
}
SridharKritha
  • 8,481
  • 2
  • 52
  • 43
0

constexpr -> Used for compile time constant. This is basically used for run time optimization.
const -> Used for run time constant.

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 25 '22 at 13:23