Reputation: 102406
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
Reputation: 29017
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
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
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