David G
David G

Reputation: 96845

What does it mean to unpack a parameter pack into another template declaration?

I don't understand how the following feature should be used. When I call A::f I can omit the template parameters, but I don't understand why.

template <typename... Args>
struct A
{
    template <Args...>
    void f() {}
};

int main()
{
    A<int, bool> a;
    a.f();
}

To be specific, what does the template <Args...> mean and why can I leave the template parameters out of the function call to f?

Upvotes: 7

Views: 510

Answers (2)

leemes
leemes

Reputation: 45725

template<typename ...Args> is a variadic template. It means, that you can specify any number of template type parameters, but I think you already know this.

Whenever Args... appears in the template code, it will be unpacked ("expanded") to the types of the instantiation. In your example, this is int, bool. So your class becomes, when fully expanded, this definition:

struct A<int, bool>
{
    template <int, bool>
    void f() {}
};

This means, A<int,bool>::f() is again templated (the arguments are unpacked into another template declaration, as you called it), but this time with non-type template parameters with the types int and bool (they're anonymous), so you could instantiate f() for example like this:

a.f<1, true>();

Unfortunately, g++ seems to have a bug and won't accept this piece of code, while it accepts your code.

clang accepts both codes. I expect that in your code, clang doesn't care if the int and bool template parameters are omitted, but it doesn't complain either when they are specified (in contrast to g++).

Usage example:

If you want to use the specified values, they can't be anonymous (obviously). You can, for example, provide a format string in f() which is used to "printf" the template values, like this:

template <Args ...values>
void f(const char *fmt) {
    std::printf(fmt, values...);
}

Then, the following code

A<int> a;
a.f<42>("The answer is %d!\n");

will print:

The answer is 42!

But, using the syntax from above (Args... being expanded to anonymous non-type template parameters), the template parameters are essentially useless.

Without specifying values, it still compiles (which surprised me!) and prints an uninitialized int value.

Upvotes: 5

aaronman
aaronman

Reputation: 18761

The reason you can leave the template arguments out is because c++11 has template argument deduction template<args ...> is a variadic template which is basically a pack of possibly different typenames. This website explains the omission of template arguments. From reading further into the deduction of non type template arguments, which the compiler can deduce I believe that the compiler is realizing that they are never used (with clang at least) and making it's deduction based on that, read the deducing non type template arguments portion of the website

Upvotes: 0

Related Questions