使用变量模板的递归计算 - gcc vs 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
结果。
Clang 的行为令人惊讶。
在 C++ 标准中变量模板实例化、全局变量和递归之间是否存在任何我遗漏的微妙交互?
或者这是一个长期存在的 Clang 错误?
顺便说一下,将 fib
标记为 constexpr
解决了问题 (on godbolt.org)。
Dynamic initialization of a non-local variable with static storage duration is unordered if the variable is an implicitly or explicitly instantiated specialization, is partially-ordered if the variable is an inline variable that is not an implicitly or explicitly instantiated specialization, and otherwise is ordered. [ Note: An explicitly specialized non-inline static data member or variable template specialization has ordered initialization. — end note ]
fib<4>
、fib<5>
和 fib<6>
是具有静态存储持续时间的非局部变量,它们是隐式实例化的特化,因此它们的动态初始化是无序的。
该行为并非未定义;必须有一些未指定的初始化顺序产生看到的输出(每个 [basic.start.dynamic]/3.3 the initializations are indeterminately sequenced). In fact, clang initializes in the following order (noting that a variable before dynamic initialization has the value 0 from static initialization):
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>
.
顺序初始化一样有效
考虑以下示例:
#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
结果。
Clang 的行为令人惊讶。
在 C++ 标准中变量模板实例化、全局变量和递归之间是否存在任何我遗漏的微妙交互?
或者这是一个长期存在的 Clang 错误?
顺便说一下,将 fib
标记为 constexpr
解决了问题 (on godbolt.org)。
Dynamic initialization of a non-local variable with static storage duration is unordered if the variable is an implicitly or explicitly instantiated specialization, is partially-ordered if the variable is an inline variable that is not an implicitly or explicitly instantiated specialization, and otherwise is ordered. [ Note: An explicitly specialized non-inline static data member or variable template specialization has ordered initialization. — end note ]
fib<4>
、fib<5>
和 fib<6>
是具有静态存储持续时间的非局部变量,它们是隐式实例化的特化,因此它们的动态初始化是无序的。
该行为并非未定义;必须有一些未指定的初始化顺序产生看到的输出(每个 [basic.start.dynamic]/3.3 the initializations are indeterminately sequenced). In fact, clang initializes in the following order (noting that a variable before dynamic initialization has the value 0 from static initialization):
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>
.