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と、変数returnタイプのコールバック、およびさまざまなタイプの1つ以上のパラメーター(最後は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

あなたが探している一般性のレベルは私には完全には明らかではありませんが、おそらくこれはあなたが始めるのに役立つでしょう:

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は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 に答える
1

これがあなたが望むものであるかどうかを確認してください。それでもreturntypeを指定する必要がありますが、ラッパー関数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つの引数を受け入れることに気づいていませんでした...明確にするために、同じ数の引数を持つすべてのに対して1つのテンプレート関数Bar00を定義する必要があります。CallCallback

于 2011-12-29T00:13:54.473 に答える
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::関数を渡してからそれらを呼び出すことだけです。メンバー関数/etcへの/からの変換はすべてstd::bindのままにしておきます。

もちろん、リターンタイプは無効ではありませんが、それは小さな詳細です。

于 2011-12-28T22:28:52.423 に答える