Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 338
mark Avatar asked Mar 10 '12 22:03

mark


People also ask

What are Variadic functions in C?

Variadic functions are functions that can take a variable number of arguments. In C programming, a variadic function adds flexibility to the program. It takes one fixed argument and then any number of arguments can be passed.

What is parameter pack in c++?

Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.

What is Pack expansion?

Pack expansion A pattern followed by an ellipsis, in which the name of at least one parameter pack appears at least once, is expanded into zero or more comma-separated instantiations of the pattern, where the name of the parameter pack is replaced by each of the elements from the pack, in order. template<class...

What are Variadic templates C++?

Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.


2 Answers

#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 )
like image 109
Howard Hinnant Avatar answered Sep 21 '22 06:09

Howard Hinnant


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.

like image 38
Luc Danton Avatar answered Sep 23 '22 06:09

Luc Danton