0

可変個引数テンプレートを使用して、アトミック マルチキャスト ライブラリ (isis2.codeplex.com) である Isis2 の静的型情報をキャプチャしています。一部の Isis2 イベントはアップコール経由で配信されます。たとえば、コーディングする場合

Group g("myGroup");
g.Handlers[UDPATE] += [](string& name, Foo& f) { ... your code };
....
g.OrderedSend(UPDATE, "John Doe", new Foo(...));

次に、グループ g で文字列と Foo オブジェクトを含む更新を含むマルチキャストを受信すると、Isis2 は Foo オブジェクトのローカル インスタンスを構築し、適切な引数を使用してこのラムダをアップコールします。

これが私のパズルです。OrderedSend への引数をスキャンするための可変長コードがあり、メッセージの作成に必要な静的型情報を取得できます。最終的に、実際の OrderedSend メソッドに引数の 1 次元配列を渡します。それぞれの引数の型、ポインター、またはデータまたはオブジェクトへの安全な参照、およびオブジェクトの場合はマーシャリング メソッドのアドレスが含まれます。しかし、可変個引数テンプレートを使用してラムダをスキャンするには、ハンドラのベクトルに追加されるオブジェクトがラムダであるという意味で、関数の「内部引数リスト」を調べる必要があります。type_traits メソッドは、タイプ「関数」のオブジェクトです。ラムダの引数リストから、string 型と Foo 型を探しています。しかし、私が見る限り、type_traits.h には引数リストにアクセスするためのものが何もありません。

GCC-11 固有のオプションは、typeid をアンマングルし、結果の文字列を解析することです。しかし、コンパイル時にラムダの引数リストにアクセスできるようにする可変個引数テンプレート機能はありますか?

4

2 に答える 2

1
template<class Sig>
struct MessageName {
  std::string name;
  MessageName() = delete;
  MessageName( std::string o ):name(o) {}
  MessageName(MessageName&&)=default;
  MessageName(MessageName const&)=default;
  MessageName& operator=(MessageName&&)=default;
  MessageName& operator=(MessageName const&)=default;
};

// trait to determine if some args are compatible:
template<class Sig, class...Ts>
struct is_compatible : std::false_type {};
template<>
struct is_compatible<void()> : std::true_type {};

template<class A0, class...Args, class T0, class...Ts>
struct is_compatible<void(A0, Args...), T0, Ts...>:
  std::integral_constant<bool,
    std::is_convertible<T0, A0>::value
    && is_compatible< void(Args...), Ts... >::value
  >
{};
struct HandlerMap {
  template<class Sig>
  void add_handler(
    MessageName<Sig> msg,
    block_deduction< std::function<Sig> > handler
  )
  {
    // ...
  }
  template<class Sig, class...Ts>
  typename std::enable_if<is_compatible<Sig, Ts...>::value>::type
  send_message( MessageName<Sig> msg, Ts&&... ts )
  {
    // ...
  }
};

UPDATEトークンはタイプである必要がありますMessageName。すべてMessageNameのは、関連付けられた署名を要求する必要があります。

MessageName< void(std::string const&, Foo const&) > UPDATE{"update"};

上記のように。

次に、ハンドラーを追加すると、 への呼び出しによりadd_handler、割り当てられた関数が必要な署名と照合され、std::function.

同様に、メッセージを送信するときに、渡されたタイプを署名に対してチェックできます。関数の本体で、引数を各シグネチャの引数の型に変換することも必要です。

これにより、可能な限り多くの型チェックがコンパイル時に行われます。これは C++ の優れたスタイルです。

于 2015-06-17T02:38:25.240 に答える
0

いいえ、それは不可能です。オブジェクトがラムダではなく、オーバーロードを持つ構造体である場合はどうなりますか? それともポリラムダ?関数オブジェクトのシグネチャが 1 つだけであると想定することはできません。複数のシグネチャを取得する方法はたくさんあります。

簡単な例を次に示します。

struct fun {
    int i;
    void operator()(int x) {}
    void operator()(float x) {} 
};

この構造体またはその引数のいずれかについて、超複雑または非 POD は何もありません。

于 2015-06-16T14:47:43.720 に答える