C++ 包装C++;C中的成员函数-Visual Studio 2013模板问题
我正在创建一个轻量级的跨平台插件框架,它在应用程序和插件之间使用C接口(通常都是用C++编写的,但并不总是这样) <> P>我的一个挑战是帮助C++应用程序和插件编写人员找到一种简单的方法来在C接口上公开C++对象功能。我的当前解决方案很简单,并使用模板来构建基于C++的成员函数的C签名函数,基于 技术细节: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
- 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;
}