54

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

#include <algorithm>

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

int main()
{
    return std::min(S::X, 0);
};

我收到以下链接器错误:

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

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

但是,如果 S 被声明为命名空间,即“命名空间 S”而不是“结构 S”,则一切都可以正常链接。

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

4

6 回答 6

38

我不认为这是一个错误。如果您将 更改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
}

这样做的原因是constexpr 可以在编译时进行评估,但不需要像这样进行评估,并且同样可以在运行时发生。它没有指示“编译器始终将符号视为表达式”,它暗示如果编译器愿意,这样做是明智和允许的。

于 2011-12-09T23:28:32.727 回答
15

这已在 C++17 中修复。

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

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

于 2018-11-17T11:50:43.243 回答
14

错误的原因已经解释过了,所以我只是添加一个解决方法。

return std::min(int(S::X), 0);

这会创建一个临时的,因此std::min可以引用它。

于 2016-04-16T22:14:33.080 回答
11

您还需要为结构(或类)之外的 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);
};
于 2018-07-04T06:38:31.797 回答
5

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

具有命名空间范围 (3.3.6) 的名称具有内部链接,如果它是 [...] 一个明确声明的变量的名称,const或者constexpr既没有明确声明extern也没有以前声明为具有外部链接 [...]。

“联动”定义如下:

当一个名称可能表示与另一个范围内的声明引入的名称相同的对象、引用、函数、类型、模板、命名空间或值时,就说它具有链接:

— 当名称具有外部链接时,它所表示的实体可以被其他翻译单元的范围或同一翻译单元的其他范围的名称引用。

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

— 当名称没有链接时,它所表示的实体不能被其他范围的名称引用。

因此,如果是namespace S,它将具有外部链接,如果是struct S,它将具有内部链接

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

于 2014-06-24T10:14:27.907 回答
0

你的理解constexpr是错误的。声明 的左值constexpr仍然是左值,声明的函数 constexpr仍然是函数。当一个函数有一个引用参数并且它被传递一个左值时,语言要求引用引用那个左值,而不是别的。(当应用于 type 的变量时,和 plain int之间实际上几乎没有区别。)constexprconst

于 2014-06-20T12:46:39.850 回答