这段代码应该使用以下方法在编译时计算近似值e(即数学常数〜2.71828183);使用静态成员变量的奇数C++模板行为
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次迭代它产生零,而不是预期的值。我已经添加了一个静态成员函数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
为什么result
没有取得预期值,而f()
呢?
根据Rotsor的评论下面,这与GCC工作,所以我想问题是,我依赖于静态初始化顺序的某种类型的未定义的行为,或者这是Visual Studio的错误?
如果使用GNU编译器编译,您的代码[works fine](http://codepad.org/TqziZEMi)。 – Rotsor 2010-06-18 11:25:50
@Rotsor:谢谢,这很有用。我已经更新了相应的问题。 – 2010-06-18 11:39:51
你不应该使标识符全部大写,它使它们看起来像宏。我甚至无法开始识别你的代码。 – Puppy 2010-06-18 11:45:10