2014-11-05 75 views
36

以下3個對gun函數的調用有什麼區別?使用可變模板擴展

template <class... Ts> void fun(Ts... vs) { 
    gun(A<Ts...>::hun(vs)...); 
    gun(A<Ts...>::hun(vs...)); 
    gun(A<Ts>::hun(vs)...); 
} 

我對使用特定示例解釋三個調用的答案感興趣。

+9

有趣的槍? – 0x499602D2 2014-11-05 22:50:48

+4

@ 0x499602D2有趣的槍,hun – chbaker0 2014-11-06 05:51:40

+0

類似的問題是這一個http://stackoverflow.com/questions/17652412/what-are-the-rules-for-the-token-in-the-context-of-variadic-模板,但下面的答案更全面地闡明瞭我的問題,更具體地說 – 2015-01-30 13:05:00

回答

57

本來我只是從字面上回答了這個問題,但我想稍微擴展一下,以便更全面地解釋如何將包擴展到什麼地方。無論如何,我都是這麼想的。

任何包立即緊跟着一個省略號只是擴展到位。所以A<Ts...>相當於A<T1, T2, ..., TN>hun(vs...)hun(v1, v2, ..., vn)相同。當它變得複雜的時候,而不是一個包,然後橢圓形,你會得到像((expr)...)。這將擴展到(expr1, expr2, ..., exprN),其中expri是指任何包被其替換爲i th版本的原始表達。所以如果你有hun((vs+1)...),那就變成hun(v1+1, v2+1, ..., vn+1)。更有趣的是expr可以包含多個包(只要它們都具有相同的尺寸!)。這就是我們如何實現標準的完美轉發模型;

foo(std::forward<Args>(args)...) 

這裏expr包含兩個包(Argsargs都是包)和擴展「迭代」在兩個:

foo(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), ..., std::forward<ArgN>(argN)); 

這種推理應能迅速地通過你的情況下散步,說,當你撥打foo(1, 2, '3')會發生什麼。

第一個,gun(A<Ts...>::hun(vs)...);擴大Ts「到位」,然後有到最後橢圓擴大的表達,所以這個要求:

gun(A<int, int, char>::hun(1), 
    A<int, int, char>::hun(2), 
    A<int, int, char>::hun('3')); 

第二個,gun(A<Ts...>::hun(vs...));到位兩側展開的包:

gun(A<int, int, char>::hun(1, 2, '3')); 

第三個,gun(A<Ts>::hun(vs)...),同時膨脹既包

[更新]爲了完整起見,gun(A<Ts>::hun(vs...)...)會叫:

gun(A<int>::hun(1, 2, '3'), 
    A<int>::hun(1, 2, '3'), 
    A<char>::hun(1, 2, '3')); 

最後,還有最後一種情況考慮,我們做得太過火省略號:

gun(A<Ts...>::hun(vs...)...); 

這不會編譯。我們擴大了Tsvs「到位」,但是我們沒有任何包可以擴展到最後的省略號。

16

下面是他們當Ts爲T,U如何擴大和VS是T,U:

gun(A<Ts...>::hun(vs)...) -> gun(A<T, U>::hun(t), A<T, U>::hun(u)) 
gun(A<Ts...>::hun(vs...)) -> gun(A<T, U>::hun(t, u)); 
gun(A<Ts>::hun(vs)...) -> gun(A<T>::hun(t), A<U>::hun(u)) 

而更多的情況,你沒有涵蓋:

gun(A<Ts>::hun(vs...)...) -> gun(A<T>::hun(t, u), A<U>::hun(t, u)) 

如果您運行的代碼下面VS14你會得到這樣的輸出:

calling gun(A<Ts...>::hun(vs)...); 
    struct A<int,double>::hun(double); 
    struct A<int,double>::hun(int); 
    gun(struct A<int,double>, struct A<int,double>); 
calling gun(A<Ts...>::hun(vs...)); 
    struct A<int,double>::hun(int, double); 
    gun(struct A<int,double>); 
calling gun(A<Ts>::hun(vs)...); 
    struct A<double>::hun(double); 
    struct A<int>::hun(int); 
    gun(struct A<int>, struct A<double>); 
calling gun(A<Ts>::hun(vs...)...); 
    struct A<double>::hun(int, double); 
    struct A<int>::hun(int, double); 
    gun(struct A<int>, struct A<double>); 

代碼:

#include <iostream> 
#include <typeinfo> 

using namespace std; 

void printTypes() {} 

template<typename T, typename... Ts> void printTypes(T, Ts... vs) { 
    cout << typeid(T).name() << (sizeof...(Ts) ? ", " : ""); 
    printTypes(vs...); 
} 

template<typename... Ts> struct A { 
    template<typename... Us> 
    static auto hun(Us... vs) { 
     cout << " " << typeid(A).name() << "::hun("; 
     printTypes(vs...); 
     cout << ");" << endl; 
     return A{}; 
    } 
}; 

template<typename... Ts> void gun(Ts... vs) { 
    cout << " gun("; 
    printTypes(vs...); 
    cout << ");" << endl; 
} 

template<typename... Ts> void fun(Ts... vs) { 
    cout << "calling gun(A<Ts...>::hun(vs)...);" << endl; 
    gun(A<Ts...>::hun(vs)...); 
    cout << "calling gun(A<Ts...>::hun(vs...));" << endl; 
    gun(A<Ts...>::hun(vs...)); 
    cout << "calling gun(A<Ts>::hun(vs)...);" << endl; 
    gun(A<Ts>::hun(vs)...); 
    cout << "calling gun(A<Ts>::hun(vs...)...);" << endl; 
    gun(A<Ts>::hun(vs...)...); 
} 

int main() { 
    fun(1, 2.0); 
} 
+0

非常感謝您的回答和代碼示例!但是,我選擇了以前的答案,因爲它提供了更多細節。 – 2014-11-06 06:39:00