2009-12-09 50 views
3

我用C++模板編寫了偶數/奇數的判斷代碼。如何理解使用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!"
被最後調用。但是,這是錯誤的。

爲什麼「嘿!」首先輸出?

回答

6

你的模板EvenOdd明確專門用於參數10只,所有其他專業化的構造函數實例化一個匿名EvenOdd爲模板參數N+1作爲其構造函數的第一個動作。

這意味着EvenOdd構造將遞歸產生匿名EvenOdd臨時對象的任何EvenOdd對象構造Print對象到模板參數10之前。

構造第11個EvenOdd對象導致輸出「Hey!」,則構造第一個對象Print

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>