clang 上的静态 constexpr 未定义引用错误

static constexpr undefined reference error on clang

以下代码在 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

在 SO 上也有类似的问题,即 未定义的引用错误,静态 constexpr 数据成员,但是 none 向我解释了为什么这段代码无法编译叮当响。上面3)中的代码有问题吗?

C++17引入了static constexpr成员变量隐式inlineP0386)的规则。在 C++17 之前不存在内联变量。

这意味着在早期的 C++ 标准中,编译器 可能 需要定义一个 static constexpr 成员变量。如果它的地址被占用,例如。

在早于 C++17 的 C++ 标准中,您可以通过单独 定义 static 变量来确保您的代码格式正确。

struct repo {
    static constexpr const char *x = "sth";
};

constexpr const char *repo::x;

编辑:

需要注意的是,优化关闭none of the examples成功link。

这是优化器的产物,有时,对一个值的引用可以被扁平化为该值本身,在这种情况下,linker 不会'不要寻找丢失的符号。

使用 https://godbolt.org/z/edj6Ed 我验证程序编译并运行 gcc >= 7,但失败并出现与 6.4 的 clang 相同的错误,前提是使用

-std=c++17

(其实我用的是-pedantic -std=c++17).

Clang++ 从版本 5.0.0 开始也可以很好地编译您的程序,这是第一个支持 C++17 的版本。它总是以 std=C++14.

失败

在引用 static constexpr 的 C++17 中发生了什么?

A constexpr specifier used in a function or static member variable (since C++17) declaration implies inline.

(参见 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

Pre-C++17,如果是ODR-used.

,则需要定义static constexpr变量

在您的示例中,x 使用 ODR,因为它作为参数传递给 pair 构造函数,后者通过引用获取值。因此,您需要对其进行定义。