constexpr const vs constexpr variables?

C++C++11ConstantsConstexpr

C++ Problem Overview


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?

C++ Solutions


Solution 1 - C++

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.

Solution 2 - C++

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.

Solution 3 - C++

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionThomas MoulardView Question on Stackoverflow
Solution 1 - C++T.C.View Answer on Stackoverflow
Solution 2 - C++Sam VarshavchikView Answer on Stackoverflow
Solution 3 - C++Michael GazondaView Answer on Stackoverflow