代码之家  ›  专栏  ›  技术社区  ›  jon hanson

带有静态成员VAR的奇数C++模板行为

  •  2
  • jon hanson  · 技术社区  · 14 年前

    这段代码应该用来计算 e

    e1 = 2 / 1
    e2 = (2 * 2 + 1) / (2 * 1) = 5 / 2   = 2.5
    e3 = (3 * 5 + 1) / (3 * 2) = 16 / 6  ~ 2.67
    e4 = (4 * 16 + 1) / (4 * 6) = 65 / 24 ~ 2.708
    ...
    e(i) = (e(i-1).numer * i + 1) / (e(i-1).denom * i)
    

    计算通过 result 但是,静态成员在2次迭代之后,它会产生0而不是期望值。我添加了一个静态成员函数f()来计算相同的值,而这不会出现相同的问题。

    #include <iostream>
    #include <iomanip>
    
    // Recursive case.
    
    template<int Iters, int Num = 2, int Den = 1, int I = 2>
    struct CalcE
    {
        static const double result;
        static double f () {return CalcE<Iters, Num * I + 1, Den * I, I + 1>::f ();}
    };
    
    template<int Iters, int Num, int Den, int I>
    const double CalcE<Iters, Num, Den, I>::result = CalcE<Iters, Num * I + 1, Den * I, I + 1>::result;
    
    // Base case.
    
    template<int Iters, int Num, int Den>
    struct CalcE<Iters, Num, Den, Iters>
    {
        static const double result;
        static double f () {return result;}
    };
    
    template<int Iters, int Num, int Den>
    const double CalcE<Iters, Num, Den, Iters>::result = static_cast<double>(Num) / Den;
    // Test it.
    
    int main (int argc, char* argv[])
    {
        std::cout << std::setprecision (8);
    
        std::cout << "e2 ~ " <<  CalcE<2>::result << std::endl;
        std::cout << "e3 ~ " <<  CalcE<3>::result << std::endl;
        std::cout << "e4 ~ " <<  CalcE<4>::result << std::endl;
        std::cout << "e5 ~ " <<  CalcE<5>::result << std::endl;
    
        std::cout << std::endl;
        std::cout << "e2 ~ " <<  CalcE<2>::f () << std::endl;
        std::cout << "e3 ~ " <<  CalcE<3>::f () << std::endl;
        std::cout << "e4 ~ " <<  CalcE<4>::f () << std::endl;
        std::cout << "e5 ~ " <<  CalcE<5>::f () << std::endl;
    
        return 0;
    }
    

    我用VS 2008和VS 2010对此进行了测试,在每种情况下都得到了相同的结果:

    e2 ~ 2
    e3 ~ 2.5
    e4 ~ 0
    e5 ~ 0
    
    e2 ~ 2
    e3 ~ 2.5
    e4 ~ 2.6666667
    e5 ~ 2.7083333
    

    为什么会这样 不产生预期值 f() 做?

    根据 Rotsor

    3 回复  |  直到 7 年前
        1
  •  1
  •   Aakash Goel    14 年前

    显然,至少在VC++中,不能依赖静态成员初始化的顺序。

    下面是一个简化的示例:

    #include <stdio.h>
    
    template<int N>
    struct one
    {
        static const int res;
    };
    
    template<>
    struct one<0>
    {
        static const int res;
    };
    
    template<int N>
    const int one<N>::res = one<N-1>::res;
    
    const int one<0>::res = 1;
    
    int main()
    {
        printf("%d\n", one<3>::res);
        printf("%d\n", one<2>::res);
        printf("%d\n", one<1>::res);
        printf("%d\n", one<0>::res);
    }
    

    0
    1
    1
    1
    

    codepad ,它产生:

    1
    1
    1
    1
    
        2
  •  0
  •   anon anon    14 年前

    e2 ~ 2
    e3 ~ 2.5
    e4 ~ 2.6666667
    e5 ~ 2.7083333
    
    e2 ~ 2
    e3 ~ 2.5
    e4 ~ 2.6666667
    e5 ~ 2.7083333
    
        3
  •  0
  •   Amnon    14 年前

    C++不喜欢非整数编译时间常数。一个可能的解决方案是使用有理算法:

    #include <iostream>
    #include <iomanip>
    
    template<int Iters, int Num = 2, int Den = 1, int I = 2>
    struct CalcE
    {
        typedef CalcE<Iters, Num * I + 1, Den * I, I + 1> res;
        enum { num = res::num, den = res::den };
        static double g() { return static_cast<double>(num) / den; }
    };
    
    template<int Iters, int Num, int Den>
    struct CalcE<Iters, Num, Den, Iters>
    {
        enum { num = Num, den = Den };
        static double g() { return static_cast<double>(num) / den; }
    };
    
    int main (int argc, char* argv[])
    {
        std::cout << std::setprecision (8);
    
        std::cout << "e2 ~ " <<  CalcE<2>::g() << std::endl;
        std::cout << "e3 ~ " <<  CalcE<3>::g() << std::endl;
        std::cout << "e4 ~ " <<  CalcE<4>::g() << std::endl;
        std::cout << "e5 ~ " <<  CalcE<5>::g() << std::endl;
        std::cout << "e5 ~ " <<  CalcE<6>::g() << std::endl;
    
        return 0;
    }