static const 整数成员的基本乐趣

Basic fun with static const integral members

考虑以下代码:

struct X {
  static const int i = 45;
};

void foo() {
  const int* k = &X::i;
}

int main() {
}

如果不打开您最喜欢的编译器,您认为尝试编译和 linking 这个简单的野兽会产生什么结果?

有些人可能会感到惊讶,它不仅取决于编译器,还取决于其优化选项!例如,在 gcc 上,代码将拒绝 link 并关闭优化,但会很乐意 link (并生成可运行的无所事事的可执行文件)并打开任何优化。

失败案例中的诊断会很有趣 - 找不到符号 X::i。启用优化的 links 将成功,因为 X::i 将被丢弃。

和问题。 编译 这段代码的编译器行为是否正确?由于 X::i 没有 linkage,编译器是否应该在被要求生成要求此符号的 linkage 的代码时抱怨?

因为你是 odr-using i 通过获取它的地址,它必须在 class:

之外定义
const int X::i ;

违反此规则属于无需诊断类别,因此这是完全有效的行为:

Informally, an object is odr-used if its address is taken, or a reference is bound to it, and a function is odr-used if a function call to it is made or its address is taken. If an object or a function is odr-used, its definition must exist somewhere in the program; a violation of that is a link-time error.

这可能取决于编译器、优化级别等...

C++ 标准草案部分 3.2 [basic.def.odr] 说:

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required

一些注意事项:

  • 捕获 ODR 违规通常是 hard problem
  • 在这种情况下,捕获它并不像看起来那么简单,因为 i 可以稍后定义或在另一个翻译单元中定义。
  • 我们需要行外定义,因为我们只需要一个定义,而声明可以重复,即如果它们是头文件的一部分。