简体   繁体   中英

Variadic Templates - different types of expansion

Andrei Alexandrescu gave an excellent talk entitled: Variadic Templates are Funadic .

He presents the following 3 expansions which are subltey different:

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

He explains:

Call 1: Expands all Ts for instatiation of class A , Then calls hun(vs) Then expands all parameters again when passing them into gun

Call 2: Expands all Ts and all vs separately

Call 3: Expnads in lock step, ie: Expand argument 1 of Ts and Argument 1 of vs Expand argument 2 of Ts and Argument 2 of vs Expand argument n of Ts and Argument n of vs

Other discussion on variadic templates only seem to cover the simple variadic class templates and variadic functions such as typesafe printf etc. I am unsure as to how these different types of expansion effect the code and where each type would be useful.

Does anyone have some examples that demonstrate the application of each type of expansion?

#include <iostream>
#include <memory>
#include <typeinfo>
#include <cstdlib>
#include <cxxabi.h>

template <typename T>
std::unique_ptr<char, void(*)(void*)>
type_name()
{
    return std::unique_ptr<char, void(*)(void*)>
           (
                __cxxabiv1::__cxa_demangle(typeid(T).name(), nullptr,
                                           nullptr, nullptr),
                std::free
           );
}

void display() {}

template <class T>
void
display()
{
    std::cout << type_name<T>().get() << ' ';
}

template <class T, class T2, class ...Tail>
void
display()
{
    std::cout << type_name<T>().get() << ' ';
    display<T2, Tail...>();
}

template <class... Ts>
struct A
{
    template <class... Us>
        static
        int
        hun(Us... us)
        {
            std::cout << "A<";
            display<Ts...>();
            std::cout << ">::hun(";
            display<Us...>();
            std::cout << ")\n";
            return 0;
        }
};

template <class ...T>
void gun(T...) {}

template <class... Ts> void fun( Ts... vs )
{
    std::cout << "gun( A<Ts...>::hun(vs)...);\n";
    gun( A<Ts...>::hun(vs)...);
    std::cout << "\ngun( A<Ts...>::hun(vs...));\n";
    gun( A<Ts...>::hun(vs...));
    std::cout << "\ngun( A<Ts>::hun(vs)...);\n";
    gun( A<Ts>::hun(vs)...);
}

int main()
{
    fun(1, 'a', 2.3);
}

Output:

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

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

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

Cases 2 and 3 really are very common in any kind of code involving variadic packs.

template<typename... T>
void f(T&&... t)
{
    // Case 2:
    auto t2 = std::tuple<T...>(t...);

    // Case 3:
    auto t3 = std::make_tuple(std::forward<T>(t)...);
}

Looking at my own code, I can't find any surviving example of case 1. I may have used it in the past in some detail namespace for a helper tempate, but I'm not sure. I don't think it's going to be common or even necessary most of the time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM