58
votes

It seems obvious that constexpr implies const and thus it is common to see:

constexpr int foo = 42; // no const here

However if you write:

constexpr char *const str = "foo";

Then GCC will spawn "warning: deprecated conversion from string constant to ‘char*’" if -Wwrite-string flag is passed.

Writing:

constexpr const char *const str = "foo";

solves the issue.

So are constexpr const and constexpr really the same?

3
This is not a duplicate of Difference between constexpr and const. Here the question is the combined usage of "constexpr const" vs "constexpr", which is totally different to the linked question.Sumudu
@Sumudu, I completely agree and I voted to re-open the question.NicholasM

3 Answers

88
votes

The issue is that in a variable declaration, constexpr always applies the const-ness to the object declared; const on the other hand can apply to a different type, depending on the placement.

Thus

constexpr const int i = 3;
constexpr int i = 3;

are equivalent;

constexpr char* p = nullptr;
constexpr char* const p = nullptr;

are equivalent; both make p a const pointer to char.

constexpr const char* p = nullptr;
constexpr const char* const p = nullptr;

are equivalent. constexpr makes p a const pointer. The const in const char * makes p point to const char.

5
votes

The error message you're seeing has nothing to do with the constexpr keyword per se.

A string literal like "foo", as in:

somefunction("foo");

The type of this string literal is const char *. The following statement:

char *const str = "foo";

This tries to assign a const char * value to a char * value. The resulting char * value is non-mutable, constant, but by that time the error already occured: an attempt to convert a const char * to a char *.

The constexpr keyword in your example is just a distraction, and has no bearing on the error.

-1
votes

No. To say they are the same means that there's no time that not using const would be valid without producing functionally identical code to a const version.

I find this useful in the creation of safe singletons. I haven't explored this fully, and would expect there are other valid uses for non-const constexpr.

As an example, here is code that requires non-const constexpr:

Start with a global definition of a variable:

int global_int_;

And now we can create a constexpr function that returns a reference to it:

constexpr int& get_global()
{
    return global_int_;
}

Now we can use that reference somewhere else:

int main()
{
    constexpr int& i{ get_global() };
    // do stuff with i
    return 0;
}

We can now use i as a non-const int. If const was implied, this would not be possible.

Since non-const constexpr is valid, if you are using a constexpr that needs to be const you will need to explicitly declare it.