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
可以稍后定义或在另一个翻译单元中定义。
- 我们需要行外定义,因为我们只需要一个定义,而声明可以重复,即如果它们是头文件的一部分。
考虑以下代码:
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
可以稍后定义或在另一个翻译单元中定义。 - 我们需要行外定义,因为我们只需要一个定义,而声明可以重复,即如果它们是头文件的一部分。