5

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
Ad N
  • 7,930
  • 6
  • 36
  • 80
  • 1
    Can you post the error? It would be helpful. – lodo Nov 13 '15 at 17:57
  • 1
    As an aside, deduced `Args&&...` forwarding to a function pointer expected `Args...` isn't a good plan. Just making sure you know that. – Yakk - Adam Nevraumont Nov 13 '15 at 20:58
  • @Yakk I must admit I could really use some more details regarding the point you are raising :) – Ad N Nov 16 '15 at 11:40
  • @adn Forwarding reference types are rarely exactly what you'd use in a completely different bit of code to represent the variables. You are using forwarding reference deduced types from variables `A...` to match against a function pointer that is not generated from those variables. Think about the 4 cases of forwarding rsference deduction, and what type the corresponding function pointer must be. If this makes no sense, brush up on what forwarding references *do* (it is not magic), or stop using them in anything but the simplest of contexts. – Yakk - Adam Nevraumont Nov 16 '15 at 12:31

3 Answers3

7

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);
}
Barry
  • 286,269
  • 29
  • 621
  • 977
  • Well, technically speaking, the first `Args...` is already in a non-deduced context. – T.C. Nov 13 '15 at 18:12
  • 2
    @T.C. Yeah, but now it's a **super** non-deduced context. [Also, I don't have a full explanation] – Barry Nov 13 '15 at 18:12
  • http://stackoverflow.com/questions/26885239/whats-the-point-of-boostmplidentityttype-here . As a sidenote I really would prefer an alias for `identity` in these contexts, like `dont_deduce`, so even if I don't understand the mechanism at least I know what the purpose is. – Karoly Horvath Nov 13 '15 at 18:31
  • 1
    @T.C. If it's a non deduced context then why does it fail? – David G Nov 13 '15 at 18:57
1

This works:

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

LIVE DEMO

101010
  • 41,839
  • 11
  • 94
  • 168
  • 1
    It does work, but the question is to try to understand why the proposed minimal example is not working ? (Since it is extracted from a way more complex system, where your proposed alternative cannot replace the expected functionality). – Ad N Nov 13 '15 at 18:06
  • @AdN Sorry, I had some important stuff and couldn't reply. It's a non deducable context, that's why it fails. But you've already have your answer. – 101010 Nov 13 '15 at 20:24
0

Edit: Rewritten answer:

The form Args..., int doesn't allow to deduce Args....

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Are you sure ? There is an explicit last `int` in `fun` signatures, I would expect it to limit `Args...` deduction to the first 2 parameters. – Ad N Nov 13 '15 at 18:03