Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forwarding arguments to template member function

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

like image 910
Vittorio Romeo Avatar asked Aug 14 '15 18:08

Vittorio Romeo


1 Answers

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.

like image 58
John Juan Calhoun Avatar answered Oct 19 '22 19:10

John Juan Calhoun