Preface: std::forward is useless here, since Args... explicitly specified. In other words, the C interface instance is no longer a template. std::forward not used in code without templates. For this reason, std::forward not used in the following solutions.
Version 1:
template <typename Base, typename Derived, typename R, typename... Args> struct c_interface_gen { template <R(Derived::*mem_fn)(Args...)> inline static R invoke(Base* pb, Args... args) { return (static_cast<Derived*>(pb)->*mem_fn)(args...); } template <R(Derived::*mem_fn)(Args...) const> inline static R invoke(const Base* pb, Args... args) { return (static_cast<const Derived*>(pb)->*mem_fn)(args...); } };
This version works. But this is by no means elegant. The main problem is the lengthy and non-intuitive syntax of using the tool.
Version 2:
template <typename Sig> struct mem_fn_sig; template <typename R, typename D, typename... Args> struct mem_fn_sig<R(D::*)(Args...)> { template <R(D::*mem_fn)(Args...)> struct mem_fn_inst { template <typename Base> struct base { inline static R invoke(Base* pb, Args... args) { return (static_cast<D*>(pb)->*mem_fn)(args...); } }; }; }; template <typename R, typename D, typename... Args> struct mem_fn_sig<R(D::*)(Args...) const> { template <R(D::*mem_fn)(Args...) const> struct mem_fn_inst { template <typename Base> struct base { inline static R invoke(const Base* pb, Args... args) { return (static_cast<const D*>(pb)->*mem_fn)(args...); } }; }; }; template <typename Sig, Sig inst, typename Base> struct c_interface_gen: mem_fn_sig<Sig>:: template mem_fn_inst<inst>:: template base<Base> {};
Obviously, this version has more code than the previous one. But the good point is that the syntax for using an object is simple and intuitive. In fact, the syntax is similar to the syntax of your source object. I just added some code to facilitate the compilation process for MSVC.
Typically, you will use the tool as follows:
... = c_interface_gen<decltype(&Derived::f), &Derived::f, Base>::invoke;
If Derived::f overloaded, you will need to explicitly specify its type as follows:
... = c_interface_gen<void(Derived::*)() const, &Derived::f, Base>::invoke;
Note that there is no need to specify const Base for the const member function. You just specify the base type. Templates will automatically figure out whether to add a const modifier or not.
The following is an example of your code using this second version:
#include <iostream> template <typename Sig> struct mem_fn_sig; template <typename R, typename D, typename... Args> struct mem_fn_sig<R(D::*)(Args...)> { template <R(D::*mem_fn)(Args...)> struct mem_fn_inst { template <typename Base> struct base { inline static R invoke(Base* pb, Args... args) { return (static_cast<D*>(pb)->*mem_fn)(args...); } }; }; }; template <typename R, typename D, typename... Args> struct mem_fn_sig<R(D::*)(Args...) const> { template <R(D::*mem_fn)(Args...) const> struct mem_fn_inst { template <typename Base> struct base { inline static R invoke(const Base* pb, Args... args) { return (static_cast<const D*>(pb)->*mem_fn)(args...); } }; }; }; template <typename Sig, Sig inst, typename Base> struct c_interface_gen: mem_fn_sig<Sig>:: template mem_fn_inst<inst>:: template base<Base> {}; // // C interface and function(s) typically defined elsewhere // #ifdef __cplusplus extern "C" { #endif // The C interface implemented by a 'greeter' struct greeter_c { void(*greet_cb)(const struct greeter_c * greeter, const char * recipient); }; // Some C function that makes use of a greeter void broadcast(const struct greeter_c * greeter) { greeter->greet_cb(greeter, "world"); } #ifdef __cplusplus } // extern "C" #endif // // A C++ class that implements the C 'greeter' interface // class Greeter : public greeter_c { public: // Constructor Greeter(const char * greeting) : m_greeting(greeting) { // Set up C interface callback by wrapping member function // !! The following line causes the Visual Studio compilation error !! greet_cb = c_interface_gen<decltype(&Greeter::greet), &Greeter::greet, greeter_c>::invoke; } // C++ member function that 'does' the greeting void greet(const char * recipient) const { std::cout << m_greeting << " " << recipient << std::endl; } private: const char * m_greeting; }; // An application that greets using a Greeter C interface int main(int argc, char * argv[]) { // Create C++ object that implements C interface Greeter a("Hello"); // Greet using Greeter C interface broadcast(static_cast<const greeter_c *>(&a)); return 0; }