1

イベント リアクターとプロアクターのタイムアウトについては、イベントの O(log(n)) ランダム アクセス削除も許可するプライオリティ キューを使用します (タイムアウトが発生するのではなく、イベントが通知/完了された場合)。を呼び出すときに効率的な削除を可能にするために、追加するクラスがインデックス (キューを指す) を持っているstd::pair<std::chrono::steady_clock::time_point, Timed *>場所を保存します。タイムアウトに関連付けられたイベント タイプが必要な場合は、. キューのとペアを返します。TimedTimedQ::Remove(Timed *p)TimedTop()Pop()

以前は、次のようなキューを使用するコードがたくさんありました

std::tie(timePt0, eventPtr0) = timeoutQ.Pop();
std::tie(timePt1, eventPtr1) = std::move(hold);

タイムアウトに関連付けることができる複数の異なるイベント タイプを最終的にサポートする必要があったためTimed *、特定のイベント タイプの代わりにキューで基本クラスを使用する前 (つまり、元々はテンプレート化されたタイプでした) は問題なく機能していました。Timedただし、eventPtr*派生型 (キューによって返される型static_castからTimed *取得できる) であるため、上記のようなコードは機能しなくなります。

これを行うための最良の方法は何だろうと思っています。現在、非常に冗長になっており、一時的な作成などの効率も懸念されています。

auto v(timeoutQ.Pop());
timePt0 = v.first;
eventPtr0 = static_cast<TimedEvent *>(v.second);
std::tie(timePt1, eventPtr1) = std::move(std::make_pair(hold.first, static_cast<TimedEvent *>(hold.second)); // I didn't literally do it like this, but I'm just trying to illustrate my struggle

私が持っていた他の唯一のアイデアは、派生したイベント クラスによってペアを返す関数をテンプレート化することでしたが、これはコード サイズの観点からは貧弱に思えます。いずれの場合も、格納されるのはポインターです。


編集: これもコンパイルしてみましたが、正しいか効率的かわかりません:

template<class D>
std::pair<std::chrono::steady_clock::time_point, D *> &&Cnvrt(std::pair<std::chrono::steady_clock::time_point, Timed *> &&in)
{
    return std::make_pair(in.first, static_cast<D *>(in.second));
}

最初の例は次のようになります

std::tie(timePt0, eventPtr0) = Cnvrt<std::remove_pointer<decltype(eventPtr0)>::type>(timeoutQ.Pop());
std::tie(timePt1, eventPtr1) = Cnvrt<std::remove_pointer<decltype(eventPtr1)>::type>(hold);
4

1 に答える 1

1

あなたCnvrtが示した は、ダングリング参照 – 古典的なUBを返します。

Dこれは、コンパイル時にも検証さstd::remove_pointer<...>::typeれ、呼び出しサイトでのマニュアルの必要性を排除する、修正された C++11 準拠のバージョンです。

template<typename D>
constexpr
std::pair<std::chrono::steady_clock::time_point, D>
Cnvrt(std::pair<std::chrono::steady_clock::time_point, Timed*> const& in) noexcept
{
  static_assert(std::is_pointer<D>{}, "D is not a pointer type");

  using derived_type = typename std::remove_pointer<D>::type;
  static_assert(std::is_base_of<Timed, derived_type>{}, "D does not derive from Timed");

  using ptr_type = typename std::remove_cv<D>::type;
  return {in.first, static_cast<ptr_type>(in.second)};
}

// ...

std::tie(timePt0, eventPtr0) = Cnvrt<decltype(eventPtr0)>(timeoutQ.Pop());
std::tie(timePt1, eventPtr1) = Cnvrt<decltype(eventPtr1)>(hold);

Online Demo

VC++ 2012 で動作するはずの実装を次に示します。

template<typename D>
std::pair<std::chrono::steady_clock::time_point, D>
Cnvrt(std::pair<std::chrono::steady_clock::time_point, Timed*> const& in) throw()
{
  static_assert(std::is_pointer<D>::value, "D is not a pointer type");

  typedef typename std::remove_pointer<D>::type derived_type;
  static_assert(std::is_base_of<Timed, derived_type>::value, "D does not derive from Timed");

  typedef typename std::remove_cv<D>::type ptr_type;
  return std::make_pair(in.first, static_cast<ptr_type>(in.second));
}

Online Demo

ここでは効率の問題はまったくありません。コンパイラが最適化をまったく行わない場合の最悪のシナリオでさえ、1 つのスカラーと 1 つのポインターのコピーにすぎません (VC++ 2012 はそれぞれを 2 回コピーする可能性がありますが、これも最適化が有効になっていない場合のみです)。 .

于 2016-01-28T13:19:32.720 に答える