Search code examples
c++variadic-templatestemplate-argument-deduction

incorrect deduction of template parameter pack


The following program does not compile:

template <unsigned int dim, unsigned int N, bool P, bool C, class... ParametersType>
void test(ParametersType&&... par)
{
}

int main()
{
    test<2, 3, true, false>(2, 1, {8, 8});
}

See it live on Coliru.

The error message

g++ -std=c++17 -O1 -Wall -pedantic -pthread main.cpp && ./a.out

main.cpp: In function 'int main()':

main.cpp:8:41: error: too many arguments to function 'void test(ParametersType&& ...)
 [with unsigned int dim = 2; unsigned int N = 3; bool P = true; bool C = false; ParametersType = {}]'

    8 |     test<2, 3, true, false>(2, 1, {8, 8});

      |                                         ^

main.cpp:2:6: note: declared here

    2 | void test(ParametersType&&... par)

      |      ^~~~

indicates that the parameter pack ParametersType... is deduced to an empty one, while I would expect it to be deduced according to the types of the arguments passed to test.

The problem is in the {8, 8} parameter passed to test. Explicitly passing a std::array to the function solves the problem:

#include <array>

template <unsigned int dim, unsigned int N, bool P, bool C, class... ParametersType>
void test(ParametersType&&... par)
{
}

int main()
{
    test<2, 3, true, false>(2, 1, std::array<int, 2>{8, 8});
}

See it live on Coliru.

Why does the compiler apparently incorrectly deduces the pack in the first example?

If the compiler is not able to deduce {8, 8} to an std::array, I would expect an "impossible to deduce" error. Why instead does the compiler deduce the pack to an empty one?


Solution

  • Template errors are hard to get right. It's just a quality of implementation. Clang for instances gives

    main.cpp:2:6: note: candidate template ignored: substitution failure 
    [with dim = 2, N = 3, P = true, C = false]: deduced incomplete pack <int, int, (no value)>
    for template parameter 'ParametersType'
    

    which is easier to understand. And yes, unless using auto, {stuff} has no type.