C++11/14 可变参数模板可以迭代函数的参数吗?
Can a C++11/14 variadic template iterate on arguments to a function?
我正在使用可变参数模板在 Isis2 中捕获静态类型信息,这是一个原子多播库 (isis2.codeplex.com)。一些 Isis2 事件是通过上行调用传递的。例如,如果您编码
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,我需要查看函数的 "inner argument list",因为被添加到处理程序向量的对象是一个 lambda:type_traits 方法将就说是"function"类型的对象吧。我在字符串和 Foo 类型之后,来自 lambda 的参数列表。但据我所知,type_traits.h 缺少访问参数列表的任何内容。
GCC-11 的一个特定选项是解开 typeid 并解析结果字符串。但是是否有一个可变参数模板功能可以让我在编译时获得 lambda 的参数列表?
不,这不可能。如果对象不是 lambda 而是具有重载的结构怎么办?还是聚λ?你不能假设函数对象只有一个签名——有很多方法可以得到不止一个。
这是一个简单的例子:
struct fun {
int i;
void operator()(int x) {}
void operator()(float x) {}
};
关于此结构或其任何参数,没有任何超级复杂或非 POD。
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++ 风格。
我正在使用可变参数模板在 Isis2 中捕获静态类型信息,这是一个原子多播库 (isis2.codeplex.com)。一些 Isis2 事件是通过上行调用传递的。例如,如果您编码
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,我需要查看函数的 "inner argument list",因为被添加到处理程序向量的对象是一个 lambda:type_traits 方法将就说是"function"类型的对象吧。我在字符串和 Foo 类型之后,来自 lambda 的参数列表。但据我所知,type_traits.h 缺少访问参数列表的任何内容。
GCC-11 的一个特定选项是解开 typeid 并解析结果字符串。但是是否有一个可变参数模板功能可以让我在编译时获得 lambda 的参数列表?
不,这不可能。如果对象不是 lambda 而是具有重载的结构怎么办?还是聚λ?你不能假设函数对象只有一个签名——有很多方法可以得到不止一个。
这是一个简单的例子:
struct fun {
int i;
void operator()(int x) {}
void operator()(float x) {}
};
关于此结构或其任何参数,没有任何超级复杂或非 POD。
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++ 风格。