递归模板无法按预期使用静态变量

str*_*QNA 6 c++ recursion templates static-members visual-c++

代码

#include <iostream>
using namespace std;

template<int n> struct Fibo { static int x; };
template<> int Fibo<0>::x = 1;
template<> int Fibo<1>::x = 1;
template<int n> int Fibo<n>::x = Fibo<n-1>::x + Fibo<n-2>::x; //marked line

int main() {
    cout << Fibo<5>::x << endl;
    cout << Fibo<4>::x << endl;
    cout << Fibo<3>::x << endl;
    cout << Fibo<2>::x << endl;
    cout << Fibo<1>::x << endl;
    cout << Fibo<0>::x << endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出

0
0
1
2
1
1
Run Code Online (Sandbox Code Playgroud)

在VC++中.(根据用户M M.它在gcc中按预期编译).当编译器到达标记的行时,n=5它不会再次编译同一行n=4,而只是将其Fibo<4>::x视为声明为

template<> int Fibo<4>::x; // x defaults to 0
Run Code Online (Sandbox Code Playgroud)

这是为什么?使用时为什么它按预期工作

template<int n> struct Fibo { enum { x = Fibo<n-1>::x + Fibo<n-2>::x }; };
template<> struct Fibo<0> { enum { x = 1 }; };
template<> struct Fibo<1> { enum { x = 1 }; };
Run Code Online (Sandbox Code Playgroud)

相反,但不是静态变量?你如何修复第一个代码(没有enum)?

Tem*_*Rex 3

标准对此说得很清楚:

14.7.1 隐式实例化[temp.inst]

9 类模板的隐式实例化不会导致该类的任何静态数据成员被隐式实例化。

main()Fibo<n>::xfor的所有调用n > 1都是显式实例化,通过斐波那契递归将隐式实例化Fibo<n-1>Fibo<n-2>但不会实例化其成员x。这意味着在这些点上,static成员x将被评估为其默认初始化0. 对于n=1n=0,编译器将看到显式初始化值 1。因此,您可以有效地得到以下计算结果

Fibo<5>::x --> Fibo<4>::x + Fibo<3>::x --> 0 + 0 = 0
Fibo<4>::x --> Fibo<3>::x + Fibo<2>::x --> 0 + 0 = 0
Fibo<3>::x --> Fibo<2>::x + Fibo<1>::x --> 0 + 1 = 1
Fibo<2>::x --> Fibo<1>::x + Fibo<0>::x --> 1 + 1 = 2
Fibo<1>::x --> 1
Fibo<0>::x --> 1
Run Code Online (Sandbox Code Playgroud)

x在评估斐波那契递归之前,您需要实例化静态成员。您可以通过static const intor enummemberx或通过函数(可能constexpr在 C++11 中)来完成此操作,如 @Jarod42 所示。