我有一个简单的类,它只是对一个类方法进行函数调用。 编译时(使用Visual Studio 2013),我收到错误消息:
错误2错误C2664:'Sleipnir :: Core :: Delegate :: Delegate(const Sleipnir :: Core :: Delegate&)':无法从'void(__ cdecl *)转换参数2(void * const,int &&)'to'void(__ cdecl *)(void * const,int&&)'d:\ programmieren \ delegate \ delegate \ delegate.h 29 1委托
这不是很有用。
我的代码:
template<typename T>
class Delegate;
template<typename R, typename... A>
class Delegate<R(A...)>
{
using TFunc = R(*)(void* const, A&&...);
private:
Delegate(void* const obj, TFunc stub)
: _objectPtr(obj),
_stubPtr(stub){}
public:
Delegate(R(*const funcPtr)(A...))
: Delegate(nullptr, functionStub<R(*)(A...)>)
{
}
private:
template <R(*funcPtr)(A...)>
static R functionStub(void* const, A&&... args)
{
return funcPtr(::std::forward<A>(args)...);
}
private:
void* _objectPtr;
TFunc _stubPtr;
};
任何人都知道为什么会发生这种情况,或者如何修复它?
答案 0 :(得分:0)
因为这条线而失败了:
using TFunc = R(*)(void* const, A&&...);
委托的公共构造函数正在推迟私有构造函数,该构造函数期望指向一个函数的指针,该函数接受一个void *后跟一个int。您正在传递一个只接受int的函数。
我怀疑你正在寻找能够处理自由函数和带有上下文参数的函数(例如this
指针)的委托。
std::function
为您处理所有这些事情。你能用std::function<R(A&&...)>
来写你的代表吗?如果是这样,您可以使用std::bind
存储成员函数回调的对象指针。
答案 1 :(得分:0)
我发现的第一个问题是你引用functionStub
作为functionStub<R(*)(A...)>
这是错误的,因为functionStub
接受一个函数指针,而不是一个类型。逻辑修复方法是将funcPtr
的地址作为functionStub<funcPtr>
传递,但也会失败。我相信这是因为函数参数不是常量表达式,因此传递funcPtr
的地址是不正确的,因为模板只能用常量表达式和类型实例化。
因此,我在评论中建议您将funcPtr
传递给functionStub
参数,方法是将其签名更改为以下内容:
static R functionStub(R (*funcPtr)(A...), void* const, A... args);
此后续问题是函数类型与TFunc
不同。您可以先std::bind()
将functionStub
改为funcPtr
来解决此问题:
: Delegate(nullptr, std::bind(&functionStub, funcPtr, placeholders::_1))
这还需要将TFunc
更改为std::function
:
using TFunc = std::function<R (void* const, A...)>;
现在我们已经摆脱了错误,但绑定只为调用提供了一个参数。 A...
可以是任意数量的参数,因此我们必须使用一些机制来存放可变数量的参数。
您可以使用this thread中显示的easy_bind()
方法。
: Delegate(nullptr, easy_bind(&functionStub, funcPtr))
最后,&functionStub
不能通过std::function
的参数推断为easy_bind()
类型,因此您可以使用make_function()
。
template <class Callable>
std::function<Callable> make_function(Callable* callable)
{
return { callable };
}
// ...
: Delegate(nullptr, easy_bind(make_function(&functionStub), funcPtr))
答案 2 :(得分:0)
现在让它工作,感谢0x499602D2
这是我的Delegate类的代码:
template <class Callable>
std::function<Callable> make_function(Callable* callable)
{
return{ callable };
}
template<typename T>
class Delegate;
template<typename R, typename... A>
class Delegate<R(A...)>
{
using TFunc = std::function<R(void* const, A...)>;
private:
Delegate(void* obj, TFunc stub)
: _objectPtr(obj),
_stubPtr(stub)
{}
public:
Delegate(R(*funcPtr)(A...))
: Delegate(nullptr, easy_bind(make_function(&functionStub), funcPtr))
{ }
template <class C>
Delegate(C* const objectPtr, R(C:: * const methodPtr)(A...))
: Delegate(objectPtr, easy_bind(make_function(&methodStub<C>), methodPtr))
{ }
template <class C>
Delegate(C* const objectPtr, R(C:: * const methodPtr)(A...) const)
: Delegate(objectPtr, easy_bind(make_function(&constMethodStub<C>), methodPtr))
{ }
public:
R operator()(A... args) const
{
return _stubPtr(_objectPtr, ::std::forward<A>(args)...);
}
private:
static R functionStub(R(*funcPtr)(A...), void* const, A... args)
{
return funcPtr(std::forward<A>(args)...);
}
template <class C>
static R methodStub(R(C::* const methodPtr)(A...), void* const objectPtr, A... args)
{
return (static_cast<C*>(objectPtr)->*methodPtr)(std::forward<A>(args)...);
}
template <class C>
static R constMethodStub(R(C::* const methodPtr)(A...) const, void* const objectPtr, A... args)
{
return (static_cast<C*>(objectPtr)->*methodPtr)(std::forward<A>(args)...);
}
private:
void* _objectPtr;
TFunc _stubPtr;
以及我如何在我的主要课程中使用它:
void test(int x)
{
std::cout << "Test - print: " << x << std::endl;
}
struct Printer
{
void print(int x){
std::cout << "Printer - print: " << x << std::endl;
}
void print2(int x) const{
std::cout << "Printer - print2: " << x << std::endl;
}
};
int main(int argc, void* args)
{
Printer printer;
Delegate<void(int)> del(&test);
Delegate<void(int)> del2(&printer, &Printer::print);
Delegate<void(int)> del3(&printer, &Printer::print2);
del(1);
del2(1);
del3(1);
}