Why is this `my::test` not deduced template parameter?

Solution 1:

With

template <typename R, typename ...Ts>
void install2(my::test<R(Ts...)> func)

and calling

install2<int, int, int>(add);

you have provided explicit template arguments for the first template parameter and two elements of the parameter pack. But there could still be more elements in the pack. Therefore the function parameter still has a type containing template parameters that need to be deduced (basically my::test<int(int, int, Ts...)>).

So template argument deduction will be applied to the argument/parameter pair and it will fail, because the function argument you are providing does not have a my::test type.

With

template <typename R, typename A, typename B>
void install2(const char name[], my::test<R(A, B)> func)

you have provided template arguments to all template parameters explicitly, so my::test<R(A, B)> func will not be a deduced context anymore.

As mentioned in the comments to the question install2<int, int, int>({add}); also works because the braces make the function argument/parameter pair a non-deduced context.


If you want to be able to call the function with explicit template arguments and without braces, you can make the function parameter always a non-deduced context, for example using C++20's std::type_identity:

template <typename R, typename ...Ts>
void install2(std::type_identity_t<my::test<R(Ts...)>> func)

However, then it is not possible anymore to call it without an explicit template argument list.

You could use both this version and the original as overloads, forwarding one to the other, to cover all situations you mention in your example code.