2014-11-05 37 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