You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于C++11的RPC参数反序列化与函数调用实现咨询

问题:基于函数签名自动实现RPC参数反序列化与调用

EDIT2:已更新底部代码及示例,用于解决最终问题(参数出现反转)
EDIT:针对「问题过多」的关闭投票,请阅读加粗部分。除参数反序列化与函数调用实现外,其余部分已有通用解决方案,仅提供背景信息。

核心需求

寻求一种简洁的参数序列化与反序列化机制,尽可能减少重复样板代码。

背景说明

我们有一款自定义ASIC,包含多个相同核心,希望为每个核心提供统一软件接口,将函数调用编组到负责特定外设的核心执行。客户端调用函数时,需封装参数并通过IPC机制发送至服务端,服务端解包后执行目标函数。

已实现的参数序列化方案

我已经实现了较为合理的参数序列化逻辑:

template<typename ... Args>
auto Serialize(uint32_t FunctionID, Args ...args )
{
    auto args_tuple = std::tuple<Args...>(args...);
    send_to_IPC_Pipe(FunctionID);
    //foreach tuple element
    //  send_to_IPC_Pipe(get<n>(args_tuple));
}

void EntryPoint(int a, float b, bool c)
{
    uint32_t uFunctionID = hash(__PRETTY_FUNCTION__);
    Serialize(uFunctionID,a,b,c);
}

我意识到每个入口点都需要重复编写类似EntryPoint的结构,但暂时无法避免。

反序列化与函数调用的瓶颈

我在反序列化并触发函数调用的机制上遇到了瓶颈。目前能想到的最佳思路如下(注:我们使用constexpr字面量运算符将函数名转换为32位哈希值):

void OnServerSideRPCReceived()
{
      uint32_t uFunctionID = get_from_IPC_Pipe<uint32_t>();
      switch(uFunctionID):
      {
           case "EntryPoint"__hash:
               //需自动从IPC管道读取参数并调用同名本地函数
               break;
      }
}

尽管能确定服务端需要调用的函数,但找不到简洁的方式,利用函数签名来驱动从IPC管道读取参数的逻辑。

我设想可以这样实现:

case "EntryPoint"_hash:
          Deserialize(EntryPoint);
          break;

其中Deserialize的期望定义如下:

template<typename F>
DeSerialize(F function)
{
    //自动获取所有参数
    function(a,b,c);
}

但我无法实现根据传入函数的参数签名自动适配模板。我知道可以手动为不同调用签名编写模板特化,但希望模板能自动完成适配。

请问有什么实现建议?


用于展示问题的简化示例代码

#include <stdint.h>
#include <stdio.h>
#include <tuple>
#include <iostream>
#include <cstring>

class ByteQueue
{
    uint8_t storage[1024];
    uint8_t *writeptr;
public:        
    template<typename T>
    void push(T &data)
    {
        memcpy(writeptr,&data,sizeof(data));
        writeptr += sizeof(data);
    }
    template<typename T>
    void pull(T&data)
    {
        memcpy(&data,storage,sizeof(data));
        uint32_t uAmountToCopy = uintptr_t(writeptr)-uintptr_t(storage)-sizeof(data);
        memmove(storage,storage+sizeof(data),uAmountToCopy);
        writeptr -= sizeof(data);
    }
    ByteQueue() {
        writeptr = storage;
    }
};

ByteQueue g_ByteQueue;

template<typename T>
void send_to_IPC_Pipe(T first)
{
    g_ByteQueue.push(first);
}

template<typename T>
T get_from_IPC_Pipe()
{
    T var;
    g_ByteQueue.pull(var);
    return var;
}


namespace detail
{
    // FNV-1a 32bit hashing algorithm.
    inline constexpr uint32_t fnv1a_32(char const *s, size_t count) 
    {
        return count ? (fnv1a_32(s, count - 1) ^ s[count - 1]) * 16777619u : 2166136261u;
    }
}    // namespace detail

inline constexpr uint32_t operator"" _hash(const char *  s, size_t count)
{
    return detail::fnv1a_32(s, count);
}

constexpr uint32_t hash(char const *s,size_t count)
{
    return detail::fnv1a_32(s,count);
}

template<typename ... Args>
void Serialize(uint32_t FunctionID, Args ... args)
{
    send_to_IPC_Pipe(FunctionID);
    //some magical syntax for C++11
    int dummy[]= { (send_to_IPC_Pipe(args),0)...};
    //hide the warning
    (void)dummy;
}

template<typename ... Args>
void Invoke(void(*function)(Args...))
{
    function(get_from_IPC_Pipe<Args>()...);
}

void MyFunction(int a, int b, int c)
{
    printf("ClientSide: %s, %d, %d, %d\n",__PRETTY_FUNCTION__,a,b,c);
    Serialize(hash(__PRETTY_FUNCTION__,strlen(__PRETTY_FUNCTION__)),a,b,c);
}

void MyFunctionServerSide(int a, int b, int c)
{
    printf("ServerSide: %s, %d, %d, %d\n",__PRETTY_FUNCTION__,a,b,c);
}

void runRPCs()
{
    uint32_t uFunctionID = get_from_IPC_Pipe<uint32_t>();
    switch (uFunctionID)
    {
        case "void MyFunction(int, int, int)"_hash:
            Invoke(MyFunctionServerSide);
            break;
    }
}

int main()
{
    MyFunction(2,4,6);
    runRPCs();
    return 0;
}

内容的提问来源于stack exchange,提问作者Russ Schultz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 21:45:05