C++ 包装C++;C中的成员函数-Visual Studio 2013模板问题

C++ 包装C++;C中的成员函数-Visual Studio 2013模板问题,c++,c,plugins,visual-studio-2013,interface,C++,C,Plugins,Visual Studio 2013,Interface,我正在创建一个轻量级的跨平台插件框架,它在应用程序和插件之间使用C接口(通常都是用C++编写的,但并不总是这样) P>我的一个挑战是帮助C++应用程序和插件编写人员找到一种简单的方法来在C接口上公开C++对象功能。我的当前解决方案很简单,并使用模板来构建基于C++的成员函数的C签名函数,基于 技术细节: Linux开发:Centos 7,g++(GCC)4.8.3 20140911 Mac开发:苹果LLVM版本6.1.0(clang-602.0.49) Windows开发:Visual St

我正在创建一个轻量级的跨平台插件框架,它在应用程序和插件之间使用C接口(通常都是用C++编写的,但并不总是这样)

<> P>我的一个挑战是帮助C++应用程序和插件编写人员找到一种简单的方法来在C接口上公开C++对象功能。我的当前解决方案很简单,并使用模板来构建基于C++的成员函数的C签名函数,基于

技术细节:

  • Linux开发:Centos 7,g++(GCC)4.8.3 20140911
  • Mac开发:苹果LLVM版本6.1.0(clang-602.0.49)
  • Windows开发:Visual Studio Express 2013更新5 CTP

前言:
std::forward
在这里是无用的,因为明确指定了
Args…
。换句话说,实例化的C接口不再是模板<代码>标准::转发在非模板代码中没有用处。因此,以下解决方案中不使用
std::forward

第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...);
  }
};
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>
{};

你能告诉我导致错误的具体代码吗?哦,有没有具体的原因让你不能直接使用
std::function
免费获得这些东西?这是在C++11中出现的,所以希望VS 2013能够提供支持?@无用:我编辑这个问题是为了让大家注意示例应用程序中导致Visual Studio失败的代码行。@无用:我如何使用std::function来实现我使用接受成员函数作为参数的模板所实现的目标?我的目标是简洁地建立一个C接口,以任何应用程序或插件编写器创建的C++对象,尽可能少的重复样板。我会想出解决办法的。工作…谢谢你的勇敢努力,但我不认为C++类有两个不同名称的函数,但是相同的签名,因为你的模板类<代码> CyIdFraceEGEG/<代码>只把返回和参数类型作为参数,而不是函数本身。假设
Greeter
有一个额外的函数
void afye(const char*recipient)const
)。当您包装它时,模板类的同一实例化中的静态变量
s\u fn\u
被覆盖,导致调用
greet\u cb()
调用成员函数
bye()
!关于
std::forward
,你说得对。谢谢。@duncan,你说得对。我不幸地没有抓住这一点。将更新答案。@duncan已更新。希望它现在能解决你的问题:-)谢谢凌西。这太棒了——通过在模板类中使用模板化静态函数,它消除了模板专业化的需要(这是Visual Studio的弱点),同时克服了需要在成员函数类型之前定义可变模板(Args)参数的问题。现在我明白了,它是如此简单(就像大多数好的解决方案一样)。事实上,我比我的原始版本更喜欢你的解决方案——它更干净。明天我会接受你的回答,到时候我可以给你一些奖励:你真的让我摆脱了困境@邓肯我很高兴我的解决方案有帮助。同时查看更新的答案。我刚刚添加了一个替代和改进的解决方案供您考虑:-)
#include <iostream>
#include <utility>

//
// 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


//
// Template magic that envelopes a C++ member
// function call in a C-signature function
//
template <typename Tc, typename F, F>
struct MemberFuncWrapper;

template <typename Tc,              // C interface structure tag
          typename T,               // C++ class, derived from Tc
          typename R,               // C++ member function return type
          typename ...Args,         // C++ member function argument types
          R (T::*f)(Args...) const> // C++ member function
struct MemberFuncWrapper<Tc, R (T::*)(Args...) const, f> {
  static R call(const Tc * tc, Args... args) {
    // Cast C structure to C++ object
    const T * t = static_cast<const T *>(tc);

    // Details such as catching/handling exceptions omitted.

    // Call C++ member function
    return ((*t).*f)(args...);
  }
};

// Repeat of the above for non-const member functions omitted


//
// 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 = MemberFuncWrapper<greeter_c,
                                 void (Greeter::*)(const char *) const,
                                 &Greeter::greet>::call;
  }

  // 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's C interface
int main(int argc, char * argv[]) {
  // Create C++ object that implements C interface
  Greeter a("Hello");

  // Greet using Greeter's C interface
  broadcast(&a);

  return 0;
}
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...);
  }
};
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>
{};
#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's C interface
int main(int argc, char * argv[]) {
  // Create C++ object that implements C interface
  Greeter a("Hello");

  // Greet using Greeter's C interface
  broadcast(static_cast<const greeter_c *>(&a));

  return 0;
}