0

次のように、含まれるオブジェクトにdeadline_timerがあり、外側のオブジェクトにハンドラー関数がある2層のオブジェクト構造があります。

class Internal
{
    asio::deadline_timer t;
public:
    void QueueTick(void (*handler)(boost::system::error_code const&))
    {
       t.expires_from_now(posix_time::millisec(250));
       t.async_wait(handler);
    }
};

class ForClients
{
    Internal I;
    void OnTick(boost::system::error_code const&) { /*...*/ }
    void Init()
    {
        I.QueueTick(boost::bind(&cdevXcite::OnTick, this, _1));
    }
};

このQueueTick()呼び出しは、MSVS 2008 でのコンパイルに失敗し、「パラメータ 1 を 'boost::_bi::bind_t' から 'void (__cdecl *)(const boost::system::error_code &)' に変換できません」というメッセージが表示されます。

timer メンバーを public にして、同じ引数で直接呼び出すI.t.async_wait()と成功します。QueueTick明らかに、ハンドラーの署名は、宣言で使用したものよりも特別です。ただし、それを定義するシンボルが見つからず、basic_deadline_timer<>テンプレート内で行われているメタプログラミングを解釈する方法がわかりません。

4

2 に答える 2

0

C++11 を使用できる場合は、次のようなことができます。

class Internal
{
    asio::deadline_timer t;

public:
    void QueueTick(const std::function<void(const boost::system::error_code&)>& handler)
    {
        t.expires_from_now(posix_time::millisec(250));
        t.async_wait(handler);
    }
};

class ForClients
{
    Internal I;
    void OnTick(const boost::system::error_code& ec) { /*...*/ }
    void Init()
    {
        I.QueueTick([this](const boost::system::error_code& ec) { OnTick(ec); });
    }
};
于 2012-06-01T22:21:53.687 に答える
0

asio タイマーasync_waitは、引数で呼び出すことができる任意の呼び出し可能な型で呼び出すことができboost::system::error_code const&ます。それを定義する単一の型はどこにもありません。文書化された引数の型で呼び出すことができる必要があります。

QueueTick パラメーターの型は、そのような呼び出し可能な型の 1 つであり、正しいシグネチャを持つ単純な古い非メンバー関数へのポインターです。

void QueueTick(void (*handler)(boost::system::error_code const&))

ただし、の結果は、その関数ポインター型に変換できないboost::bindオーバーロードされたクラス型です。operator()

これを解決するにはいくつかの方法がありますが、おそらく最も簡単なのは、async_waitそれ自体に従い、関数テンプレートとして QueueTick を記述し、任意の型を受け入れることです。

class Internal
{
  asio::deadline_timer t;
public:
  template<WaitHandle>
    void QueueTick(WaitHandle handler)
    {
      t.expires_from_now(posix_time::millisec(250));
      t.async_wait(handler);
    }
};

コードの残りの部分は変更されません。

それがオプションでない場合 (たとえば、QueueTick が仮想である必要があるため)、 with を使用boost::functionして、正しい署名の呼び出し可能なオブジェクトを保持できます。

class Internal
{
  asio::deadline_timer t;
public:
  typedef boost::function<void(boost::system::error_code const&)> handler_type;
  void QueueTick(handler_type handler)
    {
      t.expires_from_now(posix_time::millisec(250));
      t.async_wait(handler);
    }
};

これは、オブジェクトを構築するため、テンプレート バージョンと比較してわずかなオーバーヘッドがありboost::functionます。

于 2012-06-02T02:59:42.467 に答える