Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this substitution of variadic template parameter failing ? (pack before fixed arguments)

Here is a minimal example triggering the compilation error:

#include <utility>
void foo(int, double, int)
{}

template <class... Args>
void post_forwarder(void(*fun)(Args..., int), Args&&... aArgs)
{
    fun(std::forward<Args>(aArgs)..., 5);
}

int main()
{
    post_forwarder(foo, 6, 6.1); // Compilation error on instantiation
    return 0;
}

I suspect the problem is related to the fact that the variadic template parameter is expanded in the function type before the fixed int parameter, but if it is the case I cannot find a good rationale for it.

The error reported by Clang 3.6 is:

error: no matching function for call to 'post_forwarder'
note: candidate template ignored: failed template argument deduction
like image 427
Ad N Avatar asked Nov 13 '15 17:11

Ad N


2 Answers

Argument deduction fails here:

template <class... Args>
void post_forwarder(void(*fun)(Args..., int), Args&&... aArgs)
                           //  ^^^^^^^

for the general rule that parameter packs have to be at the end to be deducible. The usual solution is to wrap it in a non-deducible context, so that deduction isn't even attempted:

template <typename T>
struct identity {
    using type = T;
};

template <class... Args>
void post_forwarder(void(*fun)(typename identity<Args>::type..., int), Args&&... aArgs)
{
    fun(std::forward<Args>(aArgs)..., 5);
}
like image 139
Barry Avatar answered Oct 10 '22 18:10

Barry


This works:

template <class F, class... Args>
void post_forwarder(F f, Args&&... aArgs) {
    f(std::forward<Args>(aArgs)..., 5);
}

LIVE DEMO

like image 24
101010 Avatar answered Oct 10 '22 19:10

101010