69

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?

UpAndAdam
  • 4,515
  • 3
  • 28
  • 46
Thomas Moulard
  • 5,151
  • 2
  • 21
  • 28
  • 11
    This is not a duplicate of [Difference between `constexpr` and `const`](https://stackoverflow.com/questions/14116003/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. – Anubis Jul 24 '19 at 14:54
  • 1
    @Sumudu, I completely agree and I voted to re-open the question. – NicholasM Feb 27 '20 at 15:37

3 Answers3

109

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.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • are `constexpr const char* p = nullptr;` and `constexpr char* p = nullptr;` equivalent? – IC_ Sep 13 '21 at 11:26
  • 4
    No, they aren't the same. `constexpr const char* p = nullptr;` declares that p is a const pointer to const char data, so neither p nor the data it points to can be modified. `constexpr char* p = nullptr;` declares that p is a const pointer to char data, so p cannot be modified, but the data that p points to can be modified. – qbert220 Sep 09 '22 at 13:05
  • 1
    I think what @qbert220 wrote is essential and should be added to the answer. – Paul Apr 13 '23 at 17:36
7

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.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • While true, I think the OP is right, it _ought_ to have a bearing on the error. `constexpr` and `constexpr const` ought to be the same thing. – Mooing Duck Mar 04 '15 at 01:20
  • 1
    The problem is the conversion of a const char * to a char *. Whether the resulting value is a const, or a constexpr, is not a factor. The error already occured by that point. The same error will occur with just a plain char *foo="bar". – Sam Varshavchik Mar 04 '15 at 01:21
  • 3
    The type of `"foo"` is `const char [4]`. – T.C. Mar 04 '15 at 01:27
  • You seem to be mentally attaching `constexpr` to the pointer, but I think it's attached to the characters. I'm 100% aware that a string literal can't be converted to `char*`, but each `char` itself ought to be `constexpr`, and therefore a literal _ought to_ (logically) be assignable to `constexpr char*`. – Mooing Duck Mar 04 '15 at 01:52
  • 4
    Nope. constexpr is attached to the object being declared. The object being declared is not individual characters that the pointer points to, but the pointer itself. – Sam Varshavchik Mar 04 '15 at 02:17
-2

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.

Michael Gazonda
  • 2,720
  • 1
  • 17
  • 33
  • 3
    This is a complete red herring. The C++14 constexpr-not-implicitly-const is for member functions. – T.C. Mar 04 '15 at 01:36
  • @T.C. I provided an example of non-const constexpr without a member function, so I'm unsure what you mean. – Michael Gazonda Mar 04 '15 at 01:50
  • 1
    That has nothing to do with the C++14 change. Just like with pointers, the `constexpr` is applying to the reference itself (which is a no-op since references can't be changed anyway) rather than the object referred to. – T.C. Mar 04 '15 at 01:57
  • @T.C. You're right about the C++11/14 thing, so I fixed that. My point is that adding const to the above code would remove valid functionality, which is why const can't be implied. – Michael Gazonda Mar 04 '15 at 02:07