在尝试使用可变参数模板实现 Delegate - 类时,我遇到了一个我无法解决的问题:
/// --------------------------------------
/// @thanks God
/// Steve Reinalter
/// @author Henri Korpela aka Helixirr
/// --------------------------------------
#include <cstdio>
template<typename>
class Delegate;
template<typename Return, typename Param, typename... ParamsOther>
class Delegate<Return (Param, ParamsOther...)>{
public:
/// Constructors & destructors:
Delegate(void) = default;
Delegate(Delegate const& delegate_) = default;
Delegate(Delegate&& delegate_) = default;
/// Member functions:
Delegate& bind(Return (*function_)(Param, ParamsOther...));
template<class C>
Delegate& bind(C& c_, Return (C::*function_)(Param, ParamsOther...));
/// Member functions (overloaded operators, assignment):
Delegate& operator=(Delegate const& delegate_) = default;
Delegate& operator=(Delegate&& delegate_) = default;
/// Member functions (overloaded operators, function call):
inline Return operator()(Param param_, ParamsOther... params_other_) const;
private:
/// Member data:
Return (*_m_opFunction)(Param, ParamsOther...) = nullptr;
void* _m_opInstance = nullptr;
/// Static member functions:
template<class C, Return (C::*Function)(Param, ParamsOther...)>
static inline Return _wrap_function_member(void* instance_, Param param_, ParamsOther... params_other_);
template<Return (*Function)(Param, ParamsOther...)>
static inline Return _wrap_function_static(void*, Param param_, ParamsOther... params_other_);
};
/// Member functions:
template<typename Return, typename Param, typename... ParamsOther>
Delegate<Return (Param, ParamsOther...)>& Delegate<Return (Param, ParamsOther...)>::bind(Return (*function_)(Param, ParamsOther...)){
_m_opFunction = &_wrap_function_static<decltype(function_)>;
_m_opInstance = nullptr;
return *this;
}
template<typename Return, typename Param, typename... ParamsOther>
template<class C>
Delegate<Return (Param, ParamsOther...)>& Delegate<Return (Param, ParamsOther...)>::bind(C& c_, Return (C::*function_)(Param, ParamsOther...)){
_m_opFunction = &_wrap_function_member<C, decltype(function_)>;
_m_opInstance = &c_;
return *this;
}
/// Member functions (overloaded operators, function call):
template<typename Return, typename Param, typename... ParamsOther>
Return Delegate<Return (Param, ParamsOther...)>::operator()(Param param_, ParamsOther... params_other_) const{
return _m_opFunction(_m_opInstance, param_, params_other_...);
}
/// Static member functions:
template<typename Return, typename Param, typename... ParamsOther>
template<class C, Return (C::*Function)(Param, ParamsOther...)>
Return Delegate<Return (Param, ParamsOther...)>::_wrap_function_member(void* instance_, Param param_, ParamsOther... params_other_){
return (static_cast<C*>(instance_)->*Function)(param_, params_other_...);
}
template<typename Return, typename Param, typename... ParamsOther>
template<Return (*Function)(Param, ParamsOther...)>
Return Delegate<Return (Param, ParamsOther...)>::_wrap_function_static(void*, Param param_, ParamsOther... params_other_){
return (Function)(param_, params_other_...);
}
int f(int i_){
return i_ * 2;
}
int main(void){
Delegate<int (int)> delegate__;
delegate__.bind(&f);
printf("Result: %i\n", delegate__(8));
return 0;
}
我尝试使用C ++ 11编译器( GCC 4.7.2 )在 Ideone 上编译它,但它似乎失败了:
prog.cpp:实例化'代表&amp; Delegate :: bind(Return(*)(Param,ParamsOther ...))[with Return = int; Param = int; ParamsOther = {}]': prog.cpp:79:23:从这里要求 prog.cpp:45:5:错误:没有匹配将函数'_wrap_function_static'转换为'int(*)(int)'类型 prog.cpp:39:26:错误:候选者是:template static返回Delegate :: _ wrap_function_static(void *,Param,ParamsOther ...)[with Return(* Function)(Param,ParamsOther ...)= Function; Return = int; Param = int; ParamsOther = {}] prog.cpp:实例化'Return Delegate :: operator()(Param,ParamsOther ...)const [with Return = int; Param = int; ParamsOther = {}]': prog.cpp:80:40:从这里需要 prog.cpp:59:65:错误:从'void *'无效转换为'int'[-fpermissive] prog.cpp:59:65:错误:函数的参数太多
根据我的理解, decltype 和函数指针在这里
template<typename Return, typename Param, typename... ParamsOther>
Delegate<Return (Param, ParamsOther...)>& Delegate<Return (Param, ParamsOther...)>::bind(Return (*function_)(Param, ParamsOther...)){
_m_opFunction = &_wrap_function_static<decltype(function_)>;
_m_opInstance = nullptr;
return *this;
}
似乎导致了这个问题。当我尝试将成员函数绑定到委托时,也会发生同样的情况。为什么会这样?我究竟做错了什么?对我来说,获取函数指针的类型并使用该类型作为模板参数似乎很自然,但由于某种原因,它在这里不起作用。 这个decltype和函数指针场景有什么问题?
答案 0 :(得分:1)
以下是来自clang ++ 3.2的错误消息的第一部分:
temp.cpp:41:19: error: assigning to 'int (*)(int)' from incompatible type
'<overloaded function type>'
_m_opFunction = &_wrap_function_static<decltype(function_)>;
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
temp.cpp:75:16: note: in instantiation of member function 'Delegate<int
(int)>::bind' requested here
delegate__.bind(&f);
^
temp.cpp:35:26: note: candidate function has different number of parameters
(expected 1 but has 2)
static inline Return _wrap_function_static(void*, Param param_,...
^
temp.cpp:55:41: error: too many arguments to function call, expected 1, have 2
return _m_opFunction(_m_opInstance, param_, params_other_...);
~~~~~~~~~~~~~ ^~~~~~
temp.cpp:76:38: note: in instantiation of member function 'Delegate<int
(int)>::operator()' requested here
printf("Result: %i\n", delegate__(8));
这是因为_m_opFunction
:
Return (*_m_opFunction)(Param, ParamsOther...) = nullptr;
template<Return (*Function)(Param, ParamsOther...)>
static inline Return _wrap_function_static(void*, Param param_, ParamsOther... params_other_);
也就是说,_wrap_function_static
期望void*
然后参数转发到函数调用,而_m_opFunction
只需要函数调用的参数。
标准库解决方案:
#include <iostream>
#include <functional>
int f(int i_){
return i_ * 2;
}
struct foo
{
int m;
int f(int i) { return i * m; }
};
int main()
{
std::function<int (int)> delegate__;
delegate__ = f;
std::cout << "Result: " << delegate__(8) << std::endl;
foo o;
o.m = 21;
delegate__ = std::bind(&foo::f, std::ref(o), std::placeholders::_1);
std::cout << "Result: " << delegate__(2) << std::endl;
}
尝试修复您的方法: 注意:您不能将成员函数指针转换为“普通”函数指针(它可以使用联合或复制原始数据... UB)。更好的方法是使用多态(即虚函数和调用者对象的动态分配)。
#include <cstdio>
template<typename>
class Delegate;
template<typename Return, typename Param, typename... ParamsOther>
class Delegate<Return (Param, ParamsOther...)>{
public:
/// Constructors & destructors:
Delegate(void) = default;
Delegate(Delegate const& delegate_) = default;
Delegate(Delegate&& delegate_) = default;
/// Member functions:
Delegate& bind(Return (*function_)(Param, ParamsOther...));
template<class C>
Delegate& bind(C& c_, Return (C::*function_)(Param, ParamsOther...));
/// Member functions (overloaded operators, assignment):
Delegate& operator=(Delegate const& delegate_) = default;
Delegate& operator=(Delegate&& delegate_) = default;
/// Member functions (overloaded operators, function call):
inline Return operator()(Param param_, ParamsOther... params_other_) const;
private:
/// Member data:
Return (*_m_opFunction)(Param, ParamsOther...) = nullptr;
Return (Delegate::*_m_opMemFunction)(Param, ParamsOther...) = nullptr;
void* _m_opInstance = nullptr;
/// function wrappers:
template<class C>
static inline Return _wrap_member_function(Delegate const&, Param param_, ParamsOther... params_other_);
};
/// Member functions:
template<typename Return, typename Param, typename... ParamsOther>
Delegate<Return (Param, ParamsOther...)>& Delegate<Return (Param, ParamsOther...)>::bind(Return (*function_)(Param, ParamsOther...)){
_m_opFunction = function_;
_m_opMemFunction = nullptr;
_m_opInstance = nullptr;
return *this;
}
template<typename Return, typename Param, typename... ParamsOther>
template<class C>
Delegate<Return (Param, ParamsOther...)>& Delegate<Return (Param, ParamsOther...)>::bind(C& c_, Return (C::*function_)(Param, ParamsOther...)){
_m_opFunction = reinterpret_cast<decltype(_m_opFunction)>( &_wrap_member_function<C> );
_m_opMemFunction = reinterpret_cast<decltype(_m_opMemFunction)>( function_ );
_m_opInstance = &c_;
return *this;
}
/// Member functions (overloaded operators, function call):
template<typename Return, typename Param, typename... ParamsOther>
Return Delegate<Return (Param, ParamsOther...)>::operator()(Param param_, ParamsOther... params_other_) const{
if(nullptr == _m_opMemFunction)
{
return _m_opFunction(param_, params_other_...);
}else
{
auto f = reinterpret_cast<Return (*)(Delegate const&, Param, ParamsOther...)>( _m_opFunction );
return f(*this, param_, params_other_...);
}
}
/// function wrappers:
template<typename Return, typename Param, typename... ParamsOther>
template<class C>
Return Delegate<Return (Param, ParamsOther...)>::_wrap_member_function(Delegate<Return (Param, ParamsOther...)> const& instance_, Param param_, ParamsOther... params_other_){
Return (C::*memFuncPtr)(Param, ParamsOther...) = reinterpret_cast<decltype(memFuncPtr)>( instance_._m_opMemFunction );
return (reinterpret_cast<C*>(instance_._m_opInstance)->*memFuncPtr)(param_, params_other_...);
}
int f(int i_){
return i_ * 2;
}
struct foo
{
int m;
int f(int i) { return i * m; }
};
int main(void){
Delegate<int (int)> delegate__;
delegate__.bind(&f);
printf("Result: %i\n", delegate__(8));
foo o;
o.m = 21;
delegate__.bind(o, &foo::f);
printf("Resilt: %i\n", delegate__(2));
return 0;
}
为什么我说“设计存在缺陷”:
std::function
)
std::bind(&A::func, instance)
vs delegate__.bind(instance, &A::func)
)std::ref
(或指针)来传递引用&lt; - 更不容易出错,因为很明显您必须保持实例处于活动状态,直到调用该函数为止< / LI>
Param
和ParamOthers
?