6

编码

#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;
}

输出

0
0
1
2
1
1

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

template<> int Fibo<4>::x; // x defaults to 0

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

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 }; };

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

4

2 回答 2

3

标准对此非常明确:

14.7.1 隐式实例化 [temp.inst]

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

main()对您的所有调用Fibo<n>::xforn > 1都是显式实例化,通过 Fibonnaci 递归将隐式实例化Fibo<n-1>Fibo<n-2>不是它们的成员x。这意味着在这些点上,static成员x将被评估为其默认初始化的0. 对于n=1and n=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

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

于 2013-10-14T13:57:04.753 回答
2

我不确定是否指定了静态变量的初始化顺序template<int n> int Fibo<n>::x = Fibo<n-1>::x + Fibo<n-2>::x;...

你可以这样写:

template <int N> struct Fibo { int operator()() const { static int x = Fibo<N - 1>()() + Fibo<N - 2>()(); return x; } };

template <> struct Fibo<1> { int operator()() const { static int x = 1; return x; } };
template <> struct Fibo<0> { int operator()() const { static int x = 1; return x; } };

依赖关系得到尊重。

[编辑]

在值可能被修改的情况下(根据您的评论),您可以使用类似的技术但返回参考:

template <int N> struct Fibo {
private:
    int& operator()() { static int x = Fibo<N - 1>()() + Fibo<N - 2>()(); return x; }

public:
    int operator()() const { return const_cast<Fibo&>(*this)(); }
    // This change Fibo<0> and Fibo<1> and then update value up to Fibo<N>.
    int operator(int fibo0, int fibo1) {
        int n_1 = Fibo<N - 1>()(fibo1, fibo2);
        (*this)() = n_1 + Fibo<N - 2>()();
    }
};

template <> struct Fibo<1> {
private:
    int& operator()() { static int x = 1; return x; }
public:
    int operator()() const { return const_cast<Fibo&>(*this)(); }
    void operator(int fibo0, int fibo1) { Fibo<0>()(fibo0); (*this)() = fibo1; }
};

template <> struct Fibo<0> {
private:
    int& operator()() { static int x = 1; return x; }
public:
    int operator()() const { return const_cast<Fibo&>(*this)(); }
    void operator(int fibo0) { (*this)() = fibo0; }
};
于 2013-10-13T13:13:08.613 回答