考虑以下示例:
template <class T> class method_traits;
template <class T, class Ret, class... Arg> class method_traits<Ret(T::*)(Arg...)> {
public:
using type = Arg; // this does not work
};
template <class T> using argument_types = typename method_traits<T>::type;
template <class T> class Node {
T t;
public:
Node(Input<argument_types<decltype(&T::process)>>... inputs) { // how do I make this work?
...
}
};
Node<T>
的构造函数的参数取决于方法的参数 T::process
.所以如果类型 T
有一个方法 process
签名 float process(float a, int b)
Node<T>
构造函数的签名应如下所示:Node(Input<float> a, Input<int> b)
.
如何从 T::process
中提取参数包?在 Node
的构造函数上使用它?
最佳答案
显然你不能用这种方式保存类型列表
using type = Arg;
哪里Arg
是类型的可变列表。
但是你可以将它们保存在一个类型容器中并且std::tuple
也可以做到这一点。所以我建议修改method_traits
特化如下
template <typename T>
struct method_traits;
template <typename T, typename Ret, typename... Args>
struct method_traits<Ret(T::*)(Args...)>
{ using tTypes = std::tuple<Args...>; };
并重写argument_types
拦截 std::tuple
template <typename T>
using tTypes = typename method_traits<T>::tTypes;
现在您可以使用默认模板值和偏特化技巧定义节点
template <typename T, typename TArgs = tTypes<decltype(&T::process)>>
struct Node;
这样,实例化了一个Node<T>
对象,你有效地得到一个 Node<T, tTypes<decltype(&T::process)>
那是一个Node<T, std::tuple<Args...>>
与通缉Args...
.
因此,您可以简单地定义以下 Node
的偏特化如下
template <typename T, typename ... Args>
struct Node<T, std::tuple<Args...>>
{
T t;
Node (Input<Args> ... inputs)
{ /* do something */ }
};
下面是一个完整的工作示例
#include <tuple>
#include <type_traits>
template <typename T>
struct tWrapper
{ using type = T; };
template <typename T>
using Input = typename tWrapper<T>::type;
template <typename T>
struct method_traits;
template <typename T, typename Ret, typename... Args>
struct method_traits<Ret(T::*)(Args...)>
{ using tTypes = std::tuple<Args...>; };
template <typename T>
using tTypes = typename method_traits<T>::tTypes;
template <typename T, typename TArgs = tTypes<decltype(&T::process)>>
struct Node;
template <typename T, typename ... Args>
struct Node<T, std::tuple<Args...>>
{
T t;
Node (Input<Args> ... inputs)
{ /* do something */ }
};
struct foo
{
float process (float a, int b)
{ return a+b; }
};
int main ()
{
Node<foo> nf(1.0f, 2);
}
-- 编辑 --
正如 Julius(和 OP 本身)所指出的,此解决方案需要一个具有默认模板值的附加模板类型。
在这种简化的情况下,这不是问题,但我可以想象无法添加此额外模板参数的情况(例如:如果 Node
收到模板参数的可变列表)。
在这些情况下,Julius 提出了一种方法,使解决方案稍微复杂一点,但可以避免为 Node
添加额外的模板参数。 : 添加一个模板基类,接收 TArgs
参数,并与构造函数继承一起使用。
即:定义一个NodeBase
如下
template <typename, typename>
struct NodeBase;
template <typename T, typename ... Args>
struct NodeBase<T, std::tuple<Args...>>
{
T t;
NodeBase (Input<Args> ...)
{ /* do something */ }
};
不需要额外的模板参数,对于Node
,可以简单地写成
template <typename T>
struct Node
: public NodeBase<T, tTypes<decltype(&T::process)>>
{ using NodeBase<T, tTypes<decltype(&T::process)>>::NodeBase; };
朱利叶斯遵循这个想法,准备了a solution那(恕我直言)更好更有趣。
关于c++ - 如何在 C++ 中传递参数包?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46876119/