0

我正在使用可变参数模板来捕获 Isis2 中的静态类型信息,Isis2 是一个原子多播库 (isis2.codeplex.com)。一些 Isis2 事件是通过 upcall 传递的。例如,如果您编写代码

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

然后在组 g 中接收到一个多播,其中包含一个带有字符串和一个 Foo 对象的更新,Isis2 将构造一个 Foo 对象的本地实例,然后使用适当的参数调用这个 lambda。

所以这是我的难题。我有可变参数代码来扫描 OrderedSend 的参数,并且可以捕获构建我的消息所需的静态类型信息。我最终将一个一维参数数组传递给真正的 OrderedSend 方法,每个参数都有它的类型、指针或对数据或对象的安全引用,而对于一个对象,则是一个编组方法的地址。但是要使用可变参数模板来扫描 lambda,我需要查看函数的“内部参数列表”,因为添加到处理程序向量的对象是 lambda:type_traits 方法只会说它是“函数”类型的对象。我从 lambda 的参数列表中寻找字符串和 Foo 类型。但是据我所见, type_traits.h 缺少访问参数列表的任何内容。

GCC-11 特定的选项是解开 typeid 并解析结果字符串。但是是否有一个可变参数模板功能可以让我在编译时获得 lambda 的参数列表?

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。所有MessageNames都必须声明与它们关联的签名。

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

像上面一样。

然后,当您添加处理程序时,调用add_handler将根据所需的签名检查分配的函数,并为您提供std::function.

同样,当您发送消息时,可以根据签名检查传递的类型。您甚至应该将参数转换为函数体中每个签名的参数类型。

这将尽可能多的类型检查转移到编译时,这是很好的 C++ 风格。

于 2015-06-17T02:38:25.240 回答
0

不,这是不可能的。如果对象不是 lambda 而是具有重载的结构怎么办?还是一个polylambda?您不能假设函数对象只有一个签名 - 有很多方法可以获得多个签名。

这是一个简单的例子:

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

这个结构或它的任何参数都没有超级复杂或非 POD。

于 2015-06-16T14:47:43.720 回答