11

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?

Xeo
  • 129,499
  • 52
  • 291
  • 397
mark
  • 7,381
  • 5
  • 36
  • 61
  • possible duplicate of [Variadic Templates pack expansions](http://stackoverflow.com/questions/9182251/variadic-templates-pack-expansions) – kennytm Mar 10 '12 at 22:56
  • @KennyTM that is not a duplicate. This guy wants examples of each type of expansion (not necessarily only those three that alexandrescu showed, and what he showed is only two types of expansion (one into a template argumentlist, and one into a function argument list)). – Johannes Schaub - litb Mar 11 '12 at 13:39
  • 1
    ... but as he accepted an answer that only shows those two types of expansion, i guess either the question was imprecise or i lack understanding of questions or both... – Johannes Schaub - litb Mar 11 '12 at 13:41

2 Answers2

16
#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 )
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • The second expansion seems straight forward. The other 2 are interesting but would probably lead to confusion if used in production code. Would you expect to see this in a real world scenario? – mark Mar 10 '12 at 23:28
  • 4
    It's hard for me to say. I'm guessing we as an industry are probably still learning how to use variadic templates. A couple of years from now someone may discover a really nifty way to use the other two forms and it could become a pattern. In '98 I would have never guessed I'd be using things like `enable_if` and yet I do all the time now. C++ is a living, growing language! :-) – Howard Hinnant Mar 11 '12 at 00:42
7

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.

Luc Danton
  • 34,649
  • 6
  • 70
  • 114