使用变量模板的递归计算 - gcc 与 clang
Recursive computation using variable templates - gcc vs clang
请考虑以下示例:
#include <cstdio>
template <int N>
int fib = fib<N - 1> + fib<N - 2>;
template <> int fib<2> = 1;
template <> int fib<1> = 1;
int main()
{
std::printf("%d %d %d", fib<4>, fib<5>, fib<6>);
}
GCC 7.x、8.x、9.x 和 10.x 都打印出
3 5 8
的预期结果。因此,Clang 5.x、6.x、7.x、8.x、9.x 和 10.x 都打印出
1 3 4
。
godbolt.org 上的活生生的例子
Clang的行为令人惊讶。
变量模板实例化、全局变量和我缺少的C++标准中的递归之间是否存在任何微妙的交互?
或者这是一个长期存在的叮当虫?
顺便说一下,将fib
标记为constexpr
可以解决问题(在 godbolt.org 上(。
From [basic.start.dynamic]/1:
如果具有静态存储持续时间的非局部变量是隐式或显式实例化的专用化,则动态初始化是无序的;如果变量是不是隐式或显式实例化的内联变量,则动态初始化是部分有序的,否则是有序的。[注意:显式专用的非内联静态数据成员或变量模板专用化已有序初始化。
fib<4>
、fib<5>
和fib<6>
是具有静态存储持续时间的非局部变量,它们是隐式实例化的专用化,因此它们的动态初始化是无序的。
行为不是未定义的;必须有一些未指定的初始化顺序来生成看到的输出(根据 [basic.start.dynamic]/3.3,初始化是不确定排序的(。实际上,clang 按以下顺序初始化(注意动态初始化之前的变量在静态初始化中的值为 0(:
fib<1> = 1 (actually static-initialized under [basic.start.static]/3)
fib<2> = 1 (similarly)
fib<4> = fib<2> + fib<3> = 1 + 0 = 1
fib<3> = fib<1> + fib<2> = 1 + 1 = 2
fib<5> = fib<3> + fib<4> = 2 + 1 = 3
fib<6> = fib<4> + fib<5> = 1 + 3 = 4
这与 gcc(和 MSVC(按顺序初始化fib<3>
、fib<4>
、fib<5>
、fib<6>
相同。
相关文章:
- 奇怪的结构&GCC&clang(void*返回类型)
- 如何让 GCC/Clang 在保留标识符上出错
- Visual C++: MSVC vs. GCC+CLANG: 处理 lambda 捕获类成员变量,正确的方法是什么?
- GCC/CLang不同意模板模板参数的部分特化
- 在 gcc/clang (C++) 中获取函数范围之外的标签地址
- C++指向成员的指针的类内初始化会使 MSVC 失败(但 GCC/Clang 工作)
- ICC 中的 -O2 搞砸了汇编程序,ICC 中的 -O1 和 GCC / Clang 中的所有优化都很好
- 为什么GCC/Clang甚至在最高优化水平上也不会内联
- 在继承多个空类时,了解GCC/Clang vs MSVC2015之间的不同填充规则
- C++ MSVC/GCC/Clang编译器错误
- 这被认为是有效的C 11还是C 14?还是GCC/Clang弄错了
- GCC/Clang上的模板错误,但在MSVC上没有错误
- 如何求解与GCC/Clang不同的C 功能模板的MSVC处理(无法识别的模板定义)
- 忽略 gcc/clang 的"-Wmissing-braces"警告是否明智?
- GCC/Clang 返回元组时x86_64 C++ ABI 不匹配?
- 为什么根据 C++11 标准,std::seed_seq是不可复制的,为什么 gcc/clang 不符合?
- 我可以用更新的 gcc/clang 定位较旧的 Linux 吗?C++
- gcc/clang:错误:未知类名"异常";你是说'std::exception'
- 模板专业化和DLL:Visual Studio vs. (GCC / Clang)
- 使用GCC/CLANG跟踪代码膨胀的工具