使用可变参数模板进行扩展

Lau*_*tei 36 c++ templates variadic-templates c++11

以下3个gun函数调用有什么区别?

template <class... Ts> void fun(Ts... vs) {
  gun(A<Ts...>::hun(vs)...);
  gun(A<Ts...>::hun(vs...));
  gun(A<Ts>::hun(vs)...);
}
Run Code Online (Sandbox Code Playgroud)

我对使用特定示例解释三个调用的答案感兴趣.

Bar*_*rry 58

最初我只是简单地回答了这个问题,但我想稍微扩展一下,以便更详细地解释什么包扩展到什么.无论如何,这就是我对事物的看法.

紧接着是椭圆形的任何包只是扩展到位.所以A<Ts...>相当于A<T1, T2, ..., TN>并且hun(vs...)同样相当于hun(v1, v2, ..., vn).它变得复杂的地方是,而不是一个包后面的省略号,你得到类似的东西((expr)...).这将扩展到(expr1, expr2, ..., exprN)where expri指的是原始表达式,其中任何包替换i为它的第th个版本.所以,如果你有hun((vs+1)...),那就变成了hun(v1+1, v2+1, ..., vn+1).它变得更有趣的地方expr可以包含多个包(只要它们都具有相同的大小!).这就是我们如何实现标准的完美转发模型;

foo(std::forward<Args>(args)...)
Run Code Online (Sandbox Code Playgroud)

这里expr包含两个包(Args并且args都是包),扩展"迭代"两个:

foo(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), ..., std::forward<ArgN>(argN));
Run Code Online (Sandbox Code Playgroud)

这种推理应该可以快速浏览您的案例,例如,当您打电话时会发生什么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'));
Run Code Online (Sandbox Code Playgroud)

第二个,gun(A<Ts...>::hun(vs...));扩展两个包:

gun(A<int, int, char>::hun(1, 2, '3'));
Run Code Online (Sandbox Code Playgroud)

第三个,gun(A<Ts>::hun(vs)...)同时扩展两个包:

gun(A<int>::hun(1), 
    A<int>::hun(2), 
    A<char>::hun('3'));
Run Code Online (Sandbox Code Playgroud)

[更新]为完整起见,gun(A<Ts>::hun(vs...)...)请致电:

gun(A<int>::hun(1, 2, '3'),
    A<int>::hun(1, 2, '3'),
    A<char>::hun(1, 2, '3'));
Run Code Online (Sandbox Code Playgroud)

最后,还有最后一个案例要考虑我们在省略号上过分夸大的地方:

gun(A<Ts...>::hun(vs...)...);
Run Code Online (Sandbox Code Playgroud)

这不会编译.我们扩展了两个Ts并且vs"就地",但是我们没有剩下任何包来扩展最后的省略号.


mat*_*ort 16

以下是当Ts为T,U和vs为t时,它们如何扩展:

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))
Run Code Online (Sandbox Code Playgroud)

还有一个你没有涉及的案例:

gun(A<Ts>::hun(vs...)...) -> gun(A<T>::hun(t, u), A<U>::hun(t, u))
Run Code Online (Sandbox Code Playgroud)

如果您在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>);
Run Code Online (Sandbox Code Playgroud)

码:

#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);
}
Run Code Online (Sandbox Code Playgroud)