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.


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