以下3個對gun
函數的調用有什麼區別?使用可變模板擴展
template <class... Ts> void fun(Ts... vs) {
gun(A<Ts...>::hun(vs)...);
gun(A<Ts...>::hun(vs...));
gun(A<Ts>::hun(vs)...);
}
我對使用特定示例解釋三個調用的答案感興趣。
以下3個對gun
函數的調用有什麼區別?使用可變模板擴展
template <class... Ts> void fun(Ts... vs) {
gun(A<Ts...>::hun(vs)...);
gun(A<Ts...>::hun(vs...));
gun(A<Ts>::hun(vs)...);
}
我對使用特定示例解釋三個調用的答案感興趣。
本來我只是從字面上回答了這個問題,但我想稍微擴展一下,以便更全面地解釋如何將包擴展到什麼地方。無論如何,我都是這麼想的。
任何包立即緊跟着一個省略號只是擴展到位。所以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
包含兩個包(Args
和args
都是包)和擴展「迭代」在兩個:
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...)...);
這不會編譯。我們擴大了Ts
和vs
「到位」,但是我們沒有任何包可以擴展到最後的省略號。
下面是他們當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);
}
非常感謝您的回答和代碼示例!但是,我選擇了以前的答案,因爲它提供了更多細節。 – 2014-11-06 06:39:00
有趣的槍? – 0x499602D2 2014-11-05 22:50:48
@ 0x499602D2有趣的槍,hun – chbaker0 2014-11-06 05:51:40
類似的問題是這一個http://stackoverflow.com/questions/17652412/what-are-the-rules-for-the-token-in-the-context-of-variadic-模板,但下面的答案更全面地闡明瞭我的問題,更具體地說 – 2015-01-30 13:05:00