Search code examples
c++c++11templatesvariadic-templatestemplate-argument-deduction

Non-last parameter pack compilation error


I am trying to understand how parameter packs work in variadic template functions when they are not the last parameter. I don't get why some of my calls in my sample code doesn't work. The questions are in the comments. Should they work or I don't understand something or VS2015 update 3's compiler doesn't support them yet?

template <typename T>
double sum(T t) {
    return t;
}

template <typename T, typename... Rest>
double sum(Rest... rest, T t) {
    return t + sum(rest...);
}

template <typename T>
double sum2(T t) {
    return t;
}

template <typename T, typename... Rest>
double sum2(T t, Rest... rest) {
    return t + sum2(rest...);
}

template<typename... Args>
void func(Args..., int = 0)
{}

void func()
{
    func<int, int, int>(1, 1, 1);
    func(1, 1, 1); // why doesn't this compile?
    sum(1, 1); // why doesn't this compile?
    sum<int, int>(1, 1);
    sum<int, int, int>(1, 1, 1); // why doesn't this compile while func<int, int, int>(1, 1, 1) does?

    // why are these compile? I only changed the order of the parameters compared to sum()
    sum2(1);
    sum2(1, 1);
    sum2(1, 1, 1);
}

Solution

  • I'm not really an expert but, as far I know...

    func(1, 1, 1); // why doesn't this compile?
    

    Because, in a function template, the types of a parameter pack can be deduced only if it's in last position.

    The first call

    func<int, int, int>(1, 1, 1);
    

    works because the types of the parameter aren't deduced but are explained (Args... is int, int, int) and func() receive a fourth int (with default value zero)

    The call

    func<int, int>(1, 1, 1);
    

    works also because Args... is explained as int, int and the func() function receive a third int with not default value 1


    sum(1, 1); // why doesn't this compile?
    

    Same reason: the parameter pack isn't in last position so can't be deduced; but works

    sum<int, int>(1, 1);
    

    because T is explicated as int and Rest... as int also.


    sum<int, int, int>(1, 1, 1); // why doesn't this compile while func<int, int, int>(1, 1, 1) does?
    

    The fist level call works because T is explicated as int and Rest... as int, int; but sum<int, int, int>(1, 1, 1) call sum(rest...) that, in this case is sum(1, 1); it's sum(1, 1) that fail because Rest... isn't in last position so can't be deduced


    // why are these compile? I only changed the order of the parameters compared to sum()
    sum2(1);
    sum2(1, 1);
    sum2(1, 1, 1);
    

    Because in sum2() the parameter pack list Rest... is in last position so can be (and is) deduced.