提问者:小点点

clang上的静态Constexpr未定义参考错误


以下代码在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)中的代码是否存在问题?


共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