34

Why does this code return a warning

warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]

if

A constexpr specifier used in an object declaration or non-static member function (until C++14) implies const. A constexpr specifier used in a function or static member variable (since C++17) declaration implies inline.

(cppreference.com)

#include <cassert>    
#include <string>    
#include <iostream>    

struct A     
{    
    // warning: ISO C++ forbids converting a string constant to ‘char*’    
    static constexpr char* name_ = "A";                           
    static constexpr char* name() { return name_; };             
};                                             

int main()    
{};    

If I add a const after constexpr, the warning is gone:

#include <cassert>    
#include <string>    
#include <iostream>   



struct A     
{    
    static constexpr const char* name_ = "A";    
    static constexpr const char* name() { return name_; };    
};                                             

int main()    
{};  

With g++ --version = g++ (GCC) 8.2.1 20181127,

compilation g++ -O3 -std=c++2a -Wall main.cpp -o main.

Does the constexpr not imply const on static data members?

tmaric
  • 4,835
  • 3
  • 33
  • 65

2 Answers2

49

constexpr does imply const, but in this case it applies const to the "wrong thing".

constexpr char*

is basically the same as

char * const

which is a constant pointer to a non-const char. This won't work because string literals have the type const char[N] so it would cast away the constness of the array elements.

constexpr const char*

on the other hand, is basically the same as

char const * const

which is a constant pointer to a constant char, which is what you want as it preserves the constness of the elements.

Remy Lebeau
  • 454,445
  • 28
  • 366
  • 620
NathanOliver
  • 150,499
  • 26
  • 240
  • 331
12

There is a usual difference between a constant pointer and a pointer to constant. By making your constexpr char* you made a pointer itself a constexpr (and, of course, const), but it still attempts to point at non-const character - and this is wrong, as string literals are const. Solution:

constexpr const char* ch = "StackOverflow!";

Which declares a constexpr pointer to const.

SergeyA
  • 56,524
  • 5
  • 61
  • 116
  • 2
    I remember the rule `const` binds to the thing to its immediate left (unless its first, in which case it binds to the thing to its immediate right). In my code, I tend to favor the general case, rather than the except-to-the-general rule in the parentheses. `constexpr`, when I use it (not frequently), I always put on the left as the first thing. I've not been bitten by the OP's situation yet. – Eljay Jan 18 '19 at 17:03