C ++ - 17可变参数模板:捕获回调参数

时间:2016-05-25 14:21:46

标签: c++ variadic-templates variadic-functions

我花了很多周时间来解决这个难题,并认为我可能会将其作为对C ++可变参数模板人群的挑战。如果可以这样做,我打赌你会在10秒内告诉我如何。

假设我在C ++ 17中有一组函数,每个函数都有自己的返回类型(或void),每个函数都有自己的参数类型。为简单起见,混合了POD参数和指向类的指针,可变数量的args等。所以有两个例子:

int somefunc(int x, double d) { return x + (int)d; }
void otherfunc(Foo *a, Bar *b, int x) { ... }

我的目标是通过构建一个在这里捕获完整类型集的可变参数函数来进行没有注释的静态编译时反射。因此,对于讨论,我们可以说我们的函数是RT f类型(T1 a,T2 b,...)。我的上下文是我正在为RPC和多播系统构建一个新的(并且更好的)数据编组层,这些回调实际上将在接收到一个字节数组时完成,我需要对其进行解组并转换为正确的类型:从我的字节数组的第一个字节中提取的int,或者一个新的Foo(char *),其中Foo本身有一个工厂方法来执行提升等。

静态反射是什么意思?我想要一个const std :: list,在这里我可能会把typeid(RT).hash_code()放到我的Info类中,或者也许是指向我的每个参数类别的构造函数的指针(POD构造函数基本上会抛出传入的字节序列为int *,然后返回int;类构造函数将调用工厂方法)。

好的,长序言,现在失败的尝试:这是我的尝试。 C ++ 17根本不喜欢它(似乎正确地绑定RT但是无法绑定Rest,可能因为Rest实际上是RT捕获的整个函数类型中的参数类型列表)。有什么想法吗?

class Info
{
       int rt, at;  Info *next;
       Info(int r, int a, Info* nxt) { rt = r; at = a; next = nxt; }
};

template<typename RT>
Info *Scan(RT cb())
{
       return nullptr;
}

template<typename RT, typename T, typename Rest...> Info* Scan(RT cb(T x, Rest... args))
{
       return new Info(typeid(RT).hash_code(), typeid(T).hash_code(), Scan<RT, Rest...>(cb(args...));
};

int TestMethod(int x, int y)
{
       return 0;
}

int main()
{
       Scan(TestMethod);
       return 0;
}

2 个答案:

答案 0 :(得分:4)

为此,您不需要单独的类或递归,您可以通过在std::array调用上展开参数参数包来返回hash_code哈希码:

template <typename RT, typename... Args> 
std::array<size_t, (sizeof...(Args) + 1)> 
Scan (RT (*) (Args...)) 
{
    return { typeid(RT).hash_code(), typeid(Args).hash_code()... };
}

答案 1 :(得分:0)

#include <typeinfo>

class Info
{
    int rt, at;  Info *next;
public:
    Info(int r, int a, Info* nxt) { rt = r; at = a; next = nxt; }
};

template<typename RT>
Info *Scan() {
    return nullptr;
}

template<typename RT, typename arg, typename ...args>
Info *Scan() {
    return new Info(typeid(RT).hash_code(), typeid(arg).hash_code(), Scan<RT, args...>());
}

template<typename RT, typename ...Rest> Info* Extracter(RT (&)(Rest...))
{
    return Scan<RT, Rest...>();
}

int TestMethod(int, int)
{
    return 0;
}

int main()
{
    Extracter(TestMethod);
    return 0;
}

这使用链接的Info结构。我使用一个函数来提取目标函数的所有参数,然后使用另一个函数逐个枚举这些参数。无需在所有呼叫上携带该功能。

TartanLlama的答案虽然更优雅。