==> See the full snippet code and compilation on coliru.
I have a LiteralType class filling constexpr
requirements:
struct MyString
{
constexpr MyString(char const* p, int s) : ptr(p), sz(s) {}
constexpr char const* data() const { return ptr; }
constexpr int size() const { return sz; }
char const *ptr = 0;
int const sz = 0;
};
I use it as a constexpr static
member variable:
struct Foo
{
int size() { return str_.size(); }
constexpr static MyString str_{"ABC",3};
};
int main()
{
Foo foo;
return ! foo.size();
}
But the linker says:
(Clang-3.5 and GCC-4.9)
undefined reference to `Foo::str_'
I have to define the constexpr static
member!
(I do not specify the constructor parameters)
constexpr MyString Foo::str_;
However if the constexpr static
member had been an int
the member would not have to be defined outside the class definition. This is my understanding, but I am not sure...
int
does not need to be defined outside the class declaration but MyString
requires this?constexpr static
member in a header file? The One Definition rule tells us that we can not have more than one definition of an odr-used variable in a program. So if a variable is odr-used then you need to define it but you can not define it the header file since it may be included more than once with the whole program. Odr-use violations do not require a diagnostic message and so you can violate this rule and the compiler is not obliged to notify you.
In your case you are indeed odr-using str_
, and you can not include the definition in the header file because that would violate the one definiton rule since it can be included more than once within the program.
It is interesting to note that if you had done the following it would not have been odr-used:
return str_.size_;
You would therefore not need to define the variable, which can have some odd consequences in some examples. I doubt that really solves your problem long-term.
The odr rules are covered in the draft C++ standard section 3.2
and they say:
A variable x whose name appears as a potentially-evaluated expression ex is odr-used unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.19) that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression (Clause 5). this is odr-used if it appears as a potentially-evaluated expression (including as the result of the implicit transformation in the body of a non-static member function (9.3.1)).[...]
So str_
yield a constant expression, the lvalue-to-rvalue conversion is not applied the expression str_.size()
and it is not a discarded value expression, so it is odr-used and therefore str_
is required to be defined.
On the other hand the lvalue-to-rvalue conversion is applied to the expression str_.size_
, so it is not odr-used and does not require str_
to be defined.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With