如何使用C ++模板理解输出结果

时间:2009-12-09 05:16:19

标签: c++ templates

我用C ++模板编写了偶数/奇数的判断代码。

#include <iostream>

template <int N, int Mod2=N%2>
struct Print {
  Print() {
    std::cout << N << std::endl;
  }
};

template <int N>
struct Print<N, 0> {
  Print() {
    std::cout << "Even!" << std::endl;
  }
};

template <int N>
struct Print<N, 1> {
  Print() {
    std::cout << "Odd!" << std::endl;
  }
};

template <int N>
struct EvenOdd {
  EvenOdd() {
    EvenOdd<N+1>();
    Print<N>();
  }
};

template <>
struct EvenOdd<10> {
  EvenOdd() {
    std::cout << "Hey!" << std::endl;
  }
};

int main()
{
  EvenOdd<0>();
  return 0;
}

此代码输出:

$ ./a.out
Hey!
Odd!
Even!
Odd!
Even!
Odd!
Even!
Odd!
Even!
Odd!
Even!

我预测最后会调用

EvenOdd<10>::EvenOdd() //=> "Hey!"
。但是,这是错误的。

为什么“嘿!”首先输出?

2 个答案:

答案 0 :(得分:8)

此行为与模板无关。这是基本的递归。您在打印之前递归实例化EvenOdd 。因此,打印任何内容的第一个实例是最里面的,即EvenOdd<10>

以下是发生的事情:EvenOdd<0>做的第一件事就是实例化EvenOdd<1>。只有完成后,才会调用Print<0>。直到EvenOdd<1>完成实例化EvenOdd<2>并打印后才能完成,等等:

EvenOdd<0>
 EvenOdd<1>
  EvenOdd<2>
   EvenOdd<3>
    EvenOdd<4>
     EvenOdd<5>
      EvenOdd<6>
       EvenOdd<7>
        EvenOdd<8>
         EvenOdd<9>
          EvenOdd<10>
          std::cout << "Hey!" << std::endl;
         Print<9>
        Print<8>
       Print<7>
      Print<6>
     Print<5>
    Print<4>
   Print<3>
  Print<2>
 Print<1>
Print<0>

答案 1 :(得分:6)

您的模板EvenOdd仅针对参数10明确专门化,所有其他专业化的构造函数为模板参数EvenOdd实例化匿名N+1,作为第一个操作他们的构造者。

这意味着EvenOdd构造函数将在任何EvenOdd对象构造EvenOdd对象之前递归生成匿名Print临时对象,直到模板参数10。

构造第11个EvenOdd对象导致输出“Hey!”,然后构造第一个Print对象。