12

ideone example


I need to forward some predefined arguments plus some user-passed arguments to a member function.

#define FWD(xs) ::std::forward<decltype(xs)>(xs)

template<class T, class... Ts, class... TArgs>
void forwarder(void(T::*fptr)(Ts...), TArgs&&... xs)
{
    T instance;
    (instance.*fptr)(FWD(xs)..., 0);
    //                           ^
    // example predefined argument
}

forwarder(&example::f0, 10, 'a');   
forwarder(&example::f1, 10, "hello", 5);

This works properly for non-template member functions.

The member function pointer passed to forwarder can, however, point to template functions as well. Unfortunately, the compiler is not able to deduce the type of T in that case:

struct example
{
    void f0(int, int) { }

    template<class T>
    void f1(T&&, int) { }
};

// Compiles
forwarder(&example::f0, 10);

// Does not compile
forwarder(&example::f1, 10);

Errors:

prog.cpp:30:28: error: no matching function for call to 'forwarder(<unresolved overloaded function type>, int)'
  forwarder(&example::f1, 10);
                            ^
prog.cpp:20:6: note: candidate: template<class T, class ... Ts, class ... TArgs> void forwarder(void (T::*)(Ts ...), TArgs&& ...)
 void forwarder(void(T::*fptr)(Ts...), TArgs&&... xs)
      ^
prog.cpp:20:6: note:   template argument deduction/substitution failed:
prog.cpp:30:28: note:   couldn't deduce template parameter 'T'
  forwarder(&example::f1, 10);

Is there any way I can help the compiler deduce the correct types without changing the interface of forwarder?

If not, what's the best way of solving this issue without making the user syntax too convoluted?

EDIT: It would also be acceptable to pass the member function pointer as a template parameter, maybe through a wrapper. The target member function will always be known at compile-time. Pseudocode:

forwarder<WRAP<example::f0>>(10, 'a');
// Where WRAP can be a macro or a type alias.

ideone example

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • You can still perform a cast to solve the ambiguity problem ([cf this fork of your example](http://ideone.com/942rPt)) but I am not certain that will suit you... – Caninonos Aug 14 '15 at 18:50
  • Don't know if this will suit you, but http://coliru.stacked-crooked.com/a/3507a8671c1162c2 – David G Aug 14 '15 at 18:59
  • @Caninonos: seems too annoying to write for the user. If there is no other better solution, I could write an helper `forwarder` function and a simple macro that expands to `decltype` for all the passed arguments... but I'll keep that as a last resort. – Vittorio Romeo Aug 14 '15 at 19:00
  • @0x499602D2: That's what I've been doing before passing a member function pointer... but the syntax gets really boilerplate-y for simple functions. – Vittorio Romeo Aug 14 '15 at 19:02
  • 2
    Template type deduction from function arguments works independently for each argument. If you need the types of the passed arguments in order to deduce (or fix) the type of the (member) function pointer, you could perform the deduction in two steps; syntactically e.g. `forward(10, 'a').to(example::f0)`, where `to` is defined like `template auto to( R (C::*)(ForwardedArgs&&..., PredefinedArgs...) );` Note that this might need various combinations of cv- and reference-qualifiers. Function pointers are quite inconvenient. – dyp Aug 14 '15 at 21:41
  • Or, as you probably know, there's the C++14 perfect forwarding lambda wrapper: `[](auto&& inst, auto&&... args) -> decltype(auto) { return forward(inst).f0(forward(args...)); }` – dyp Aug 14 '15 at 21:46

1 Answers1

1

I compiled your code in gcc 4.9 by providing template arguments to the member function pointer; like this

int main(){
// Compiles
forwarder(&example::f0, 10);
//Does not compile
forwarder(&example::f1, 10);
//Does compile, instantiate template with int or what ever you need
forwarder(&example::f1<int>,10)
}

I believe what is going on is that you need to instantiate the template member function. does that change your interface too much? I think any answer will revolve around instantiating that member template somehow.