jww
jww

Reputation: 102406

Why must I use const with constexpr for a static class function?

I'm trying to understand what I am seeing while testing a change. The platform is openSUSE 42 with GCC 4.8, but it could affect others. The test code and error follows.

$ cat test.cxx 
#include <string>

#if (__cplusplus >= 201103L)
#  define STATIC_CONSTEXPR static constexpr
#  define CONSTEXPR constexpr
#else
#  define STATIC_CONSTEXPR static const
#  define CONSTEXPR
#endif

struct Name
{
  STATIC_CONSTEXPR char* GetName() {return "XXX";}
};

int main(int argc, char* arv[])
{
  const char* name = Name::GetName();
  return 0;
}

And:

$ g++ -O3 -std=c++11 test.cxx -o test.exe
test.cxx: In static member function ‘static constexpr char* Name::GetName()’:
test.cxx:13:44: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
   STATIC_CONSTEXPR char* GetName() {return "XXX";}
                                            ^

Adding the following does not clear it:

struct Name
{
  STATIC_CONSTEXPR char* const GetName() {return "XXX";}
};

And adding the following does clear it:

struct Name
{
  STATIC_CONSTEXPR const char* GetName() {return "XXX";}
};

According to Does static constexpr variable make sense?:

Every variable declared constexpr is implicitly const but const and static are almost orthogonal (except for the interaction with static const integers.)

I thought I mostly understood constexpr but I'm obviously missing something (again). As I understand it, the C++ committee believes a value like "XXX" in the reproducer can somehow change after the file is saved even though its impossible under the laws of the physical universe as we currently understand them. However, to combat the problem, they gave us constexpr. An alternate explanation is here, but I have to admit I don't see the finer details that makes the difference.

Why am I seeing the warning, and why do I effectively need static constepr const to squash it?


$ uname -a
Linux opensuse-42 4.1.27-27-default #1 SMP PREEMPT Fri Jul 15 12:46:41 UTC 2016 (84ae57e) x86_64 x86_64 x86_64 GNU/Linux
opensuse-42:~$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib64/gcc/x86_64-suse-linux/4.8/lto-wrapper
Target: x86_64-suse-linux
Configured with: ../configure --prefix=/usr ... --host=x86_64-suse-linux
Thread model: posix
gcc version 4.8.5 (SUSE Linux) 

Upvotes: 0

Views: 494

Answers (3)

constexpr has nothing to do with it.

char *foo() { return "ABC"; }

will give the same warning. "ABC" is a string literal, and is of type const char[4] (array of four constant char). Like any other array, it will readily decay into a pointer of type char const * (pointer to constant char).

For string literals (only), there is also a deprecated conversion to char * (pointer to non-const char) - that is what your function is using, and that is what GCC doesn't like. The fix is either:

char const *foo() ...

or (equivalently)

const char *foo() ...

Upvotes: 2

Rakete1111
Rakete1111

Reputation: 49028

A string literator "..." is of type const char[], i.e. a array to a const characters. It can decay to const char* if needed.

You're getting the warning because you are using a deprecated conversion from const char* to char*/char* const. It doesn't matter that the function is constexpr, it only applies to the function itself, not the return value. It doesn't make sense to specify constexpr on the return value, because it is either already constexpr because of the function, or not.

So, your code is equivalent of writing

char* return_value = "XXX";
char* const return_value = "XXX";

Because none of those pointers point to a const char, you'll get a warning.

Upvotes: 3

krzaq
krzaq

Reputation: 16431

constexpr on a function declaration means that the function is constexpr, not its return type.

So your problem really boils down to the following syntax being wrong:

char * foo = "bar";

Since C++11 this conversion from char const[] to char* is flat out illegal, and has been deprecated since C++98.

Making the pointer const, as opposed to pointer to const is explored more in-depth here.

So, to return a string literal you need to use char const*. static and constexpr are not related to this problem at all.

Upvotes: 8

Related Questions