templatestemplate-argument-deductiontype-deduction

variadic template argument deduction, cannot match struct in argument


I can't work this out.

I have a template class integer that has in its template parameter its value, and I want to add together n integers of this class. I can successfully get the int value from the class in the base case, but it fails otherwise.

template <int Value>
struct integer {};

template<int A, typename ...Rest>
auto constexpr add(integer<A>, Rest...) {
    if constexpr (sizeof...(Rest) > 0)
        return A + add(Rest...);
    else
        return A;
}

int main(){

    auto constexpr y = add(integer<1>{}); // base case
    auto constexpr x = add(integer<1>{}, integer<2>{});

    return 0;
}

My guess is that something is wrong with the parameters of the meta function

template<int A, typename ...Rest>
auto constexpr add(integer<A>, Rest...) {...}

but I just can't figure out what, in my mind it should always be able to deduce that its argument is an integer, and it shouldn't even instantiate if there are 0 arguments, yet that seems to be the case in the error logs:

(8, 17) :   error C2144 : syntax error : 'integer<2>' should be preceded by ')'
(19) :      message: see reference to function template instantiation 'auto add<1,integer<2>>(integer<1>,integer<2>)' being compiled
(8, 13) :   error C2672 : 'add' : no matching overloaded function found
(7, 1) :    error C2780 : 'auto add(integer<Value>,Rest...)' : expects 2 arguments - 0 provided
(7) :       message: see declaration of 'add'
(8, 17) :   error C2144 : syntax error : 'integer<2>' should be preceded by ';'
(7, 1) :    error C2059 : syntax error : ')'
(19, 52) :  error C3313 : 'x' : variable cannot have the type 'const void'

[1


Solution

  • add is a function, not a metafunction, in the sense that you've designed it to take values (not types); in other words you call it like add(someValue) (not like add<SomeType>, fwiw).

    So, the call to add(Rest...) is syntactically wrong becaues you're passing a type instead of a value to add; you should, instead, give that parameter a name, say rest, and use that in the call:, as in add(rest...).