我有这个帮助器类,我用它来调用期望静态C函数的代码的成员方法。这个特殊的“版本”与Windows LPTHREADROUTINE回调兼容,将DWORD (class::method) (void *)
函数作为参数,如下所示:
CreateThread(NULL, 0, runThreadFunction<SomeClass>, makeThreadInfo(&myClass, &SomeClass::ThreadFunction, NULL), 0, NULL);
我希望整个事情都是通用的,我知道它可以用新的C ++ 11标准来完成,但是我无法将其完全删除。
#pragma once
#include <stdafx.h>
template <typename C>
struct ThreadInfo
{
// we have an object
C* obj;
// and that object has a function that takes void* and returns DWORD, and so is suitable for a threadproc (except for it being a member function)
DWORD (C::* function)(void*);
// and we have any amount of extra data that we might need.
void* data;
// default copy c-tor, d-tor and operator= are fine
ThreadInfo(C* o, DWORD (C::*func)(void*), void* d) : obj(o), function(func), data(d)
{
}
};
template <typename C>
DWORD WINAPI RunThreadFunction(void* data)
{
shared_ptr<ThreadInfo<C> > ti((ThreadInfo<C>*)data);
//ThreadInfo<C>* ti = (ThreadInfo<C>*) data;
return ((ti->obj)->*(ti->function))(ti->data);
}
template <typename C>
void* MakeThreadInfo(C* o, DWORD (C::* f)(void*), void* d)
{
return (void*)new ThreadInfo<C>(o, f, d);
}
我尝试将MakeThreadInfo函数的界面更改为:
template <typename C, typename R, typename... P>
void* MakeThreadInfo(C* o, std::function<R(P&...)> f, void* d)
这似乎是要走的路,但我无法将此值传递到上游。
这是我想要的:
给定一个带有MyMethod方法的MyClass类,以及一个 variable 的回调返回类型和不同类型的一个或多个参数(最后一个是{{ 1}}),我怎么能用尽可能少的boeplating将某些传递给回调并让它依次调用MyClass :: MyMethod。
举例说明:
void *userData
typedef bool (*Callback1)(void *userData);
typedef int (*Callback2)(bool param, void *userData);
void TheirLibrary::Function1(Callback1 callback, void *userData);
void TheirLibrary::Function2(Callback2 callback, void *userData);
class MyClass
{
bool MyMethod1(void *userData);
int MyMethod2(bool someParam, void *userData);
void DoSomething()
{
Function1(CreateGenericCPointer(&MyClass::MyMethod1), &MyClass);
Function2(CreateGenericCPointer(&MyClass::MyMethod2), &MyClass);
}
}
的有效实施是什么?
答案 0 :(得分:1)
我并不完全清楚你正在寻找什么级别的通用性,但也许这会让你开始:
typedef std::function<DWORD()> ThreadFuncT;
DWORD WINAPI RunThreadFunction(void* data)
{
std::unique_ptr<ThreadFuncT> tf(static_cast<ThreadFuncT*>(data));
return (*tf)();
}
template<typename F>
ThreadFuncT* MakeThreadFunction(F&& f)
{
return new ThreadFuncT(std::forward<F>(f));
}
// ...
auto myClass = std::make_shared<SomeClass>(/* ... */);
CreateThread(
nullptr,
0,
RunThreadFunction,
MakeThreadFunction([=]() { return myClass->ThreadFunction(nullptr); }),
0,
nullptr
);
请注意,因为myClass
是std::shared_ptr<>
并且是按值捕获的,所以即使SomeClass
超出范围之前,基础myClass
的生命周期也会正常终止线程完成执行(,只要 RunThreadFunction
最终被调用)。
编辑:这是另一种方法(未经测试,可能是语法错误):
template<typename R>
R WINAPI RunThreadFunction(void* data)
{
typedef std::function<R()> ThreadFuncT;
std::unique_ptr<ThreadFuncT> tf(static_cast<ThreadFuncT*>(data));
return (*tf)();
}
template<typename F>
auto MakeThreadFunction(F&& f) -> std::function<decltype(f())()>*
{
return new std::function<decltype(f())()>(std::forward<F>(f));
}
// ...
auto myClass = std::make_shared<SomeClass>(/* ... */);
auto f = [=]() { return myClass->ThreadFunction(nullptr); };
CreateThread(
nullptr,
0,
RunThreadFunction<decltype(f())>,
MakeThreadFunction(std::move(f)),
0,
nullptr
);
答案 1 :(得分:1)
看看这是不是你想要的。您仍然需要指定返回类型,但很好(在我看来)指定为struct
的模板参数,其中包含static
包装函数。如果你需要TTst
更高的灵活性,你仍然可以改进它 - 我不确定你要如何定义要调用的成员函数,所以我将它们的签名保持为callback
。 / p>
#include <iostream>
typedef int (*TFoo00)( void * );
typedef bool (*TFoo01)( int, void * );
void Bar00( TFoo00 fnc, void * ud )
{
std::cout << "Bar00" << std::endl;
fnc( ud );
}
void Bar01( TFoo01 fnc, void * ud )
{
std::cout << "Bar01 " << std::endl;
fnc( -1, ud );
}
class TTst;
template< typename PResult >
struct TWrap
{
static PResult Call( void * ud )
{
std::cout << "TWrap::Call( P00 )" << std::endl;
return ( static_cast< TTst * > ( ud )->Foo00() );
}
template< typename P00 >
static PResult Call( P00 u00, void * ud )
{
std::cout << "TTst::Call( P00, P01 )" << std::endl;
return ( static_cast< TTst * > ( ud )->Foo01( u00 ) );
}
};
class TTst
{
public:
int Foo00( void )
{
std::cout << "TTst::Foo00" << std::endl;
return ( 0 );
}
bool Foo01( int u00 )
{
std::cout << "TTst::Foo01 : " << u00 << std::endl;
return ( u00 != 0 );
}
void Do( void )
{
Bar00( TWrap< int >::Call, this );
Bar01( TWrap< bool >::Call, this );
}
};
int main( void )
{
TTst lT;
lT.Do();
return ( 0 );
}
编辑:修改Bar01
的参数 - 我没有注意到它接受2个参数为Bar00
...只是为了澄清,你需要为所有人定义一个模板Call
函数Callback
具有相同数量的参数。
答案 2 :(得分:0)
编辑:这不是OP需要的。 OP需要通用版本。
为什么不一直使用std :: function?
看起来像
std::function<void(void)> myFunc = std::bind(&Class::memberFunc,&classInstance);
CreateThread(NULL,0,runStdFunction, new std::function<void(void)>(myFunc),0,NULL);
然后,runStdFunction将像pie
一样简单为简单起见,我使用typedef std::function<void(void)> voidFunction
。
void runStdFunction(void *data)
{
std::unqiue_ptr<voidFunction> func (static_cast<voidFunction*>(data));
(*func)();
}
这个想法很简单,你所做的只是传递std :: functions然后调用它们。 将所有转换成/从成员函数/ etc转到std :: bind。
当然,您的返回类型不是空的,但这是一个小细节。