Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Having a constexpr static string gives a linker error

The following program gives me a link-time error:

#include <iostream>

struct Test { static constexpr char text[] = "Text"; };

int main()
{
    std::cout << Test::text << std::endl; // error: undefined reference to `Test::text'
}

The error message is

/tmp/main-35f287.o: In function `main':
main.cpp:(.text+0x4): undefined reference to `Test::text'
main.cpp:(.text+0x13): undefined reference to `Test::text'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Ok. Let's try to fix that: I add a definition outside the struct body:

#include <iostream>

struct Test { static constexpr char text[] = "Text"; };
constexpr char Test::text[] = "Text";

int main()
{
    std::cout << Test::text << std::endl;
}

Clang gives me the following error message.

main.cpp:4:35: error: static data member 'text' already has an initializer
    constexpr char Test::text[] = "Text";
                                  ^
main.cpp:3:50: note: previous initialization is here
    struct Test { static constexpr char text[] = "Text"; };

Oh, well, I thought, now I know what you want:

#include <iostream>

struct Test { static constexpr char text[]; };
constexpr char Test::text[] = "Text";

int main()
{
    std::cout << Test::text << std::endl;
}

And again an error:

main.cpp:3:41: error: declaration of constexpr static data member 'text' requires an initializer
    struct Test { static constexpr char text[]; };

And there the dog bites its own tail. :(

Is there a way to use compile-time constant character arrays that are declared inside a class? The reason, I want the data inside a class, is that I need a type traits class that helps me do template stuff.

like image 785
Ralph Tandetzky Avatar asked Jan 14 '16 14:01

Ralph Tandetzky


2 Answers

As said in comments, this version works fine:

struct Test { static constexpr auto text = "Text"; };

But text will be a const char* instead of a char[].

like image 42
vincentp Avatar answered Oct 17 '22 00:10

vincentp


Should work:

#include <iostream>

struct Test { static constexpr char text[] = "Text"; };
constexpr char Test::text[];

int main()
{
    std::cout << Test::text << std::endl;
}

In standard (n4140 §9.4.2/3) you can find:

A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. —end note ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.

like image 72
marcinj Avatar answered Oct 17 '22 00:10

marcinj