类静态constexpr的C++链接器错误

Tra*_*kel 46 c++ linker constexpr c++11

我正在编译以下简单程序g++-4.6.1 --std=c++0x:

#include <algorithm>

struct S
{
    static constexpr int X = 10;
};

int main()
{
    return std::min(S::X, 0);
};
Run Code Online (Sandbox Code Playgroud)

我收到以下链接器错误:

/tmp/ccBj7UBt.o: In function `main':
scratch.cpp:(.text+0x17): undefined reference to `S::X'
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

我意识到内联定义的静态成员没有定义符号,但我在(可能是有缺陷的)印象中使用constexpr告诉编译器始终将符号视为表达式; 所以,编译器会知道传递对符号的引用是不合法的S::X(出于同样的原因,你不能引用文字10).

但是如果S被声明为命名空间,即"命名空间S"而不是"struct S",那么一切都很好.

这是一个g++错误还是我仍然需要使用技巧来解决这个烦恼?

Fle*_*exo 34

我不认为这是一个错误.如果更改constexprconst,则仍然会失败,并出现完全相同的错误.

你已声明S::X,但未在任何地方定义,因此没有存储空间.如果你对它做任何事情需要知道它的地址那么你也需要在某处定义它.

例子:

int main() {
      int i = S::X; // fine
      foo<S::X>(); // fine
      const int *p = &S::X; // needs definition
      return std::min(S::X, 0); // needs it also
}
Run Code Online (Sandbox Code Playgroud)

这样做的原因是constexpr 可以在编译时进行评估,但不需要对其进行评估,也可以在运行时进行评估.它没有指示"编译器总是将符号视为表达式",它暗示如果编译器感觉它是合理的,也是允许的.

  • 你只需要一个`S :: X`的定义,因为`std :: min`通过引用获取它的参数.如果按值使用其参数,则不需要定义,因为,通过[basic.def.odr] p2,需要在潜在评估的上下文中提到的变量定义"除非它是满意的对象出现在常量表达式(5.19)和左值到右值转换(4.1)的要求立即应用",在这种情况下就是这样. (20认同)

Vla*_*adV 13

已经解释了出错的原因,所以我只想添加一个解决方法.

return std::min(int(S::X), 0);
Run Code Online (Sandbox Code Playgroud)

这会创建一个临时的,所以std::min可以参考它.


Tra*_*s3r 10

这已在C ++ 17中修复。

https://en.cppreference.com/w/cpp/language/static

如果将静态数据成员声明为constexpr,则它是隐式内联的,不需要在命名空间范围内重新声明。没有初始化程序的重新声明(以前是必需的,如上所示)仍然是允许的,但已弃用。


jci*_*loa 7

您还需要为struct(或类)外部的constexpr成员提供一个定义,但是这次没有其值。参见此处:https//en.cppreference.com/w/cpp/language/static

#include <algorithm>

struct S
{
    static constexpr int X = 10;
};

constexpr int S::X;

int main()
{
    return std::min(S::X, 0);
};
Run Code Online (Sandbox Code Playgroud)


Alb*_*ert 5

在C ++标准(最新工作草案)中,它表示:

带有名称空间范围(3.3.6)的名称是内部链接,如果它是显式声明的变量的名称,const或者constexpr既没有显式声明的变量extern也没有以前声明具有外部链接的变量的名称。

“链接”的定义如下:

当一个名称可能表示与另一个作​​用域中的声明引入的名称相同的对象,引用,函数,类型,模板,名称空间或值时,该名称具有链接关系:

—当一个名称具有外部链接时,它所表示的实体可以通过其他翻译单位范围或同一翻译单位其他范围内的名称进行引用。

—当一个名称具有内部链接时,它表示的实体可以由同一翻译单位中其他作用域的名称引用。

—当一个名称没有链接时,其表示的实体无法被其他作用域中的名称引用。

因此,在情况下namespace S,它将具有外部链接,在情况下struct S,它将具有内部链接

具有外部链接的符号需要在某个翻译单元中明确定义符号。