首页 文章

C -17可变参数模板:捕获回调参数的返回类型和参数类型

提问于
浏览
0

我花了好几个星期来解决这个难题,并认为我可能会把它作为对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,其中我可能会把类似idid(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 回答

  • 4

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

    template <typename RT, typename... Args> 
    std::array<size_t, (sizeof...(Args) + 1)> 
    Scan (RT (*) (Args...)) 
    {
        return { typeid(RT).hash_code(), typeid(Args).hash_code()... };
    }
    
  • 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的答案虽然更优雅 .

相关问题