【发布时间】:2013-05-01 21:28:39
【问题描述】:
在尝试使用可变参数模板实现 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: 在'Delegate& Delegate::bind(Return (*)(Param, ParamsOther ...)) 的实例化中 [with Return = int;参数 = 整数;参数其他 = {}]': prog.cpp:79:23:从这里需要 prog.cpp:45:5: 错误: 没有匹配转换函数‘_wrap_function_static’到类型‘int (*)(int)’ prog.cpp:39:26: 错误: 候选是: 模板静态返回委托::_wrap_function_static(void*, Param, ParamsOther ...) [with Return (* Function)(Param, ParamsOther ...) = Function;返回 = 整数;参数 = 整数;参数其他 = {}] prog.cpp:在“Return Delegate::operator()(Param, ParamsOther ...) const [with Return = int;参数 = 整数;参数其他 = {}]': 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 和函数指针场景有什么问题?
【问题讨论】:
-
完全不清楚您要做什么。您将函数指针传递给
bind,但bind从不使用其参数的值。您是否计划以后能够调用传递的函数? -
template<Return (*Function)(Param, ParamsOther...)> static inline Return _wrap_function_static /*...*/期望函数指针作为非类型模板参数。&_wrap_function_static<decltype(function_)>提供函数指针类型作为模板参数。 -
哦,顺便说一句。为什么不使用
std::bind和std::function? -
我不认为你可以将你的
bind和你的包装机制结合起来:bind没有函数指针作为非类型模板参数,因此只能访问运行时指针。您的包装机制需要在编译时访问指针(以实例化适当的包装器)。您可以用检查_m_opInstance == nullptr替换包装(本质上只区分成员函数和非成员函数),但 IMO 的设计可以说是有缺陷的。 -
@DyP:“bind 没有函数指针作为非类型模板参数,因此只能在运行时访问指针”。现在我看到了问题,模板无法在运行时解析,只能在编译时解析。悲伤,但可以理解的原因。但是为什么编译器没有检测到这个错误而不是“没有匹配转换函数'_wrap_function_static'到类型'int(*)(int)'?编译器在这里很难弄清楚吗?顺便说一句,为什么要你认为这个设计有缺陷吗?
标签: c++ c++11 function-pointers member-function-pointers decltype