以下代码在Visual Studio 2019和gcc 10.2(以及其他gcc版本)上编译良好,具有-std=c 11
,但在clang(版本9、10和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;
}
clang的错误是:
... undefined reference to `repo::x'
clang-11: error: linker command failed with exit code 1 (use -v to see invocation)
Compiler returned: 1
在这方面也有类似的问题,例如未定义的引用错误、静态constexpr数据成员,但没有一个问题可以向我解释为什么这段代码不能在clang上编译。上述3)
中的代码是否存在问题?
C17引入了以下规则:静态Constexpr
成员变量隐式地内联
(P0386)。C 17之前不存在内联变量。
这意味着在早期的C标准中,编译器可能需要定义static constexpr
成员变量。例如,如果取其地址。
在C 17之前的C标准中,您可以通过单独定义static
变量来确保代码格式良好。
struct repo {
static constexpr const char *x = "sth";
};
constexpr const char *repo::x;
编辑:
应该注意的是,关闭优化后,没有一个示例能够成功链接。
有时,对值的引用可以平坦到值本身,这是优化器的一个工件,在这种情况下,链接器不会查找丢失的符号。
在C 17之前,如果它是ODR使用的,你需要有一个静态Constexpr
变量的定义。
在您的示例中,x
是ODR使用的,因为它作为参数传递给对
构造函数,该构造函数通过引用获取值。因此,你需要一个定义。
使用https://godbolt.org/z/edj6Ed我验证了程序是否编译
-std=c++17
(实际上我用的是-pedian-std=c 17
)。
从5.0版开始,Clang还可以很好地编译程序。0,第一个支持C 17。当std=C 14时,它总是失败。
在C17中,引用静态constexpr的是什么?
在函数或静态成员变量(自C17)声明中使用的Constexpr说明符意味着内联。
(见https://en.cppreference.com/w/cpp/language/constexpr )
另见:https://www.codingame.com/playgrounds/2205/7-features-of-c17-that-will-simplify-your-code/inline-variables