The following code compiles fine on Visual Studio 2019 and on gcc 10.2 (and other gcc versions) with -std=c++11
but fails on clang (versions 9, 10 and 11).
#include <map>
#include <string>
struct repo {
static constexpr const char *x = "sth";
};
int main() {
// 1) This compiles
std::map<std::string, int> m1 = { {repo::x, 3} };
// 2) This compiles
std::map<std::string, std::string> m2 = { std::make_pair(repo::x, "") };
// 3) This does not compile on clang
std::map<std::string, std::string> m3 = { {repo::x, ""} };
return 0;
}
The error from clang is:
... undefined reference to `repo::x'
clang-11: error: linker command failed with exit code 1 (use -v to see invocation)
Compiler returned: 1
There are similar questions on SO on this, i.e. Undefined reference error, static constexpr data member, but none that explain to me why this code does not compile on clang. Is there an issue with the code in 3)
above?
C++17 introduces the rule that static constexpr
member variables are implicitly inline
(P0386). Inline variables didn't exist before C++17.
This means that in earlier C++ standards, a compiler may need a static constexpr
member variable to be defined. If its address is taken, for example.
In C++ standards earlier than C++17, you can ensure that your code is well-formed, by separately defining the static
variable.
struct repo {
static constexpr const char *x = "sth";
};
constexpr const char *repo::x;
Edit:
It should be noted that with optimizations off, none of the examples successfully link.
It is an artifact of the optimizer that sometimes, a reference to a value can be flattened to the value itself, in which case the linker won't look for the missing symbol.
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