如果我在一个翻译单元中用非默认值初始化一个constexpr
变量foo
,然后在另一个翻译单元中用foo
初始化另一个constexpr
变量bar
,是否可以在foo
之前初始化bar
,从而导致由零或默认初始化foo
初始化的bar
。 即与非 constexpr 情况(静态初始化顺序惨败生效)不同,将编译器和链接器分析依赖关系排序以保证正确的结果?
此外,constexpr 变量模板会受到怎样的影响?它们的初始化顺序在单个翻译单元中未定义。
C++17个标准答案优先。
更新:下面是一个最小的例子。它有效;这就是问题所在。在这一点上,我 99% 确定这是安全的,不会受到静态初始化顺序惨败 (TSIOF)的影响。但是,由于该问题的极端,阴险性质,我需要确认这是可以的。我相信这段代码不会受到 TSIOF 的影响,因为 y.h 包含在 x.h 订单中,a
和b
在 x.cc 翻译单元中。但是,AFAIU有2个翻译单元:一个包含a,另一个包含b。此外,AFAI-sort-of-U 不会产生a
错误的多重定义,因为静态关键字赋予了内部链接,但a
仍然具有全局范围。
编译方式:
clang++ -std=c++17 x.cc y.cc #or g++
可能的输出:
in foo
可能的输出:
assertion failed (core dumped)
文件 x.cc:
#include "x.h"
int main(){ assert(b == 42); foo(); }
文件 x.h:
#pragma once
#include "y.h"
static constexpr int b = a+1;
文件 y.cc:
#include "y.h"
#include <iostream>
void foo(){
std::cout << " in foo n";
}
文件 Y.H:
#pragma once
static constexpr int a=41;
void foo();
这个程序保证输出in foo
吗?
由于这个问题无法通过示例来回答,因此确实需要语言律师提供相关的标准报价
这个问题是关于跨翻译单元的 STIOF。关于模板变量翻译单元中 STIOF 的一个相关的、未回答的问题在这里
在您的示例中,不存在可能的问题,因为 y.cc 中的a
与 x.cc 中的a
变量不同。因此,没有发生交叉翻译单元链接。
事实上,constexpr 变量之间不可能有交叉翻译单元链接。constexpr
的全部意义在于该值是在编译时计算的。
换句话说,constexpr 必须在我们仍在隔离编译翻译单元时解析为一个值。
因此,静态初始化顺序惨败隐式不适用于constexpr
变量,并且标准无需提及在这种情况下该怎么做。
编辑:根据要求,该标准的相关部分是10.1.5(9)[dcl.constexpr]
在任何 constexpr 变量声明中,完整表达式 初始化应为常量表达式 (8.20)。
这导致 8.20 (1) [expr.const] 具有以下注释:
[ 注意:常量表达式可以在翻译过程中计算。
这是下一页半条款背后的理由,但本身就足以排除交叉翻译单元引用。