2

我有这个助手类,我用它来调用需要静态 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,以及一个变量返回类型的回调和一个或多个不同类型的参数(最后一个是 a void *userData),我怎样才能在尽可能少的样板化的情况下将一些东西传递给回调和让它依次调用 MyClass::MyMethod。

为了显示:

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);
    }
}

什么是有效的实现CreateGenericCPointer

4

3 回答 3

1

看看这是不是你想要的。您仍然必须指定返回类型,但是(在我看来)它很好地指定struct为该保存static包装函数的模板参数。如果您需要更高程度的灵活性,您仍然可以改进它TTst- 我不确定您要如何定义要调用的成员函数,所以我将它们的签名保留为callback's。

#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具有相同数量参数的 's 定义一个模板化函数。

于 2011-12-29T00:13:54.473 回答
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
);

请注意,因为myClassis astd::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
);
于 2011-12-28T22:28:10.980 回答
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 将像馅饼一样简单

为了简单起见,我正在使用typedef std::function<void(void)> voidFunction

void runStdFunction(void *data)
{
   std::unqiue_ptr<voidFunction> func (static_cast<voidFunction*>(data));
   (*func)();
}

这个想法很简单,你所做的就是传递 std::functions 然后调用它们。将所有与成员函数/等的转换留给 std::bind。

当然,您的返回类型不是 void,但这是一个小细节。

于 2011-12-28T22:28:52.423 回答