C++ 按名称调用不同签名的方法

C++ 按名称调用不同签名的方法,c++,c++11,c++14,C++,C++11,C++14,我有一组使用std::function的委托,这些委托指向具有不同签名的函数。我希望能够在运行时使用字符串键检索这些委托。我似乎不能使用映射,因为它们指向具有不同签名的函数。如果没有switch语句,我可以拥有这样的功能吗 例如,现实世界的用例是RPC系统。他们真的只是让方法具有相同的签名还是使用代码生成 E:与所选答案相关的有用链接,需要相当长的时间才能掌握 查找表和std::map的问题是所有函数指针必须具有相同的签名 然而,围绕这一点有一个复杂的解决方案。它涉及函数对象(函子)和

我有一组使用
std::function
的委托,这些委托指向具有不同签名的函数。我希望能够在运行时使用字符串键检索这些委托。我似乎不能使用映射,因为它们指向具有不同签名的函数。如果没有switch语句,我可以拥有这样的功能吗

例如,现实世界的用例是RPC系统。他们真的只是让方法具有相同的签名还是使用代码生成

E:与所选答案相关的有用链接,需要相当长的时间才能掌握


查找表和
std::map
的问题是所有函数指针必须具有相同的签名

然而,围绕这一点有一个复杂的解决方案。它涉及函数对象(函子)和基类

让我们定义基本函子类:

struct Base_Parameters;

struct Base_Functor
{
  virtual void execute(Base_Parameter * p_parameters) = 0;
};
这解决了如何声明
std::map

typedef std::map<std::string, Base_Functor *> Function_Key_Container;
现在的问题是将参数传递给函数。
我还没有完全解决这个问题,但这里有一些建议:

  • 使用boost::variant——一个变量记录
  • Base\u参数创建一个子项,并在函数对象中使用
    
    dynamic_cast
    Base_参数
    指针转换为指针 添加到子参数

从类型包开始:

template<class...Ts>struct types{
  using type=types;
  enum{count = sizeof...(Ts)};
};
template<class T> struct tag{using type=T;};
为我们提供
types
中类型
T
的偏移量。在发送端使用它将您的类型映射到列表中的索引

另一方面,我们有:

template<class types, size_t n>
struct type_at;
template<class types, size_t n>
using type_at_t=typename type_at<types,n>::type;
template<class T0, class...Ts>
struct type_at<types<T0, Ts...>,0>: tag<T0> {};
template<class T0, class...Ts, size_t n>
struct type_at<types<T0, Ts...>,n>:
  type_at<types<Ts...>, n-1>
{};
然后

一旦我们写好了,我们就可以为我们的函数表存储一个从字符串到一个
erased\u func\t
的映射

我们查找
erased\u func\t
。我们使用上述反序列化基础设施从传入的参数生成
std::vector
。我们调用它,如果失败则抛出异常

鲍勃是你叔叔

如果你想发回答案,你需要输入erase返回到wire格式,并更改
erased_func_t
以返回通过wire发回所需的
wire_数据,而不是
boost::any
。那可能是最好的

以上代码都没有经过测试。有些编译器需要C++14(没有那么多,大部分是
\u t
别名),有些声称支持C++11的编译器不支持我编写的
magic\u switch
实现(我相信除了
\u t
别名之外,它几乎是纯C++11)。但如果更详细的话,也可以编写一个等效的


最后,像许多事情一样,从头开始编写RPC协议通常不是一个好主意。我错过了上面的一个重要步骤。< /p>你如何调用从地图中检索的函数?C++是静态类型的,不能调用不知道签名的函数。您可能会尝试使用
boost::any
,但我认为您的RPC可能需要一个通用的签名用于所有函数。@但我的意思是:您将如何调用
调用
?因为您问过:一个典型的RPC实现(例如DCE/RPC或Microsoft DCOM)会让您使用一种特殊的语言描述您的外部接口(接口定义语言,IDL),然后由专用工具(IDL编译器)处理。此工具生成代理和存根函数-具有正确签名的函数,用于处理其参数的序列化和反序列化。客户端调用代理,代理神奇地调用另一端的存根,存根反过来调用服务器的实现。您不能将
std::array
,而
Param
作为模板。Y对于某些具体类型,您只能使用
std::array
,我会寻找一种“后期绑定”的方法函数对象实例的参数,但除此之外,这正是我建议的方法。
std::index_序列
std::index_序列
回答得很好!在第五个代码片段中,什么是
max
?@quen它构建了一个用于高效切换的跳转表:
max
是有效的
i
值(转换为编译时常数)是半开区间
[0,max)
。在下一个代码段中,我们将
max
设置为类型包中的类型数。
template<size_t n> using index=std::integral_constant<size_t, n>;

template<class types, class T>
struct index_in;
template<class...Ts, class T>
struct index_in<types<T, Ts...>, T>:index<0> {};
template<class T0, class...Ts, class T1>
struct index_in<types<T0, Ts...>, T1>:index<
  index_in<types<Ts...>, T1>::value+1
> {};
template<class types, size_t n>
struct type_at;
template<class types, size_t n>
using type_at_t=typename type_at<types,n>::type;
template<class T0, class...Ts>
struct type_at<types<T0, Ts...>,0>: tag<T0> {};
template<class T0, class...Ts, size_t n>
struct type_at<types<T0, Ts...>,n>:
  type_at<types<Ts...>, n-1>
{};
template<class types>
struct to_any {
  template<size_t n>
  struct worker {
    boost::any operator()( wire_data w )const{
      using protocol_ns::read;
      return read( w, (type_at_t<types,n>*)nullptr );
    }
  };
};
namespace details {
  template<template<size_t>class action, class indexes>
  struct magic_switch;
  template<template<size_t>class action, size_t... Is>
  struct magic_switch<action, std::index_sequences<Is...>>
  {
    template<class...Ts, class R=std::result_of_t< action<max>(Ts...) >>
    R operator()(size_t i, Ts&&... ts)const {
      using entry = R(*)(std::remove_reference<Ts>*...);
      entry table[] = {
        [](std::remove_reference<Ts>*...args)->R{
          return action<Is>{}( std::forward<Ts>(*args)... );
        }...
      };
      if (i > sizeof(table)/sizeof(entry))
        throw std::out_of_range("i");
      return table[i]( (&ts)... );
    }
  };
}
template<template<size_t>class action, size_t max>
struct magic_switch:
  details::magic_switch<action,std::make_index_sequence<max>>
{};
magic_switch<
  to_any<all_types_supported>::template worker, 
  all_types_supported::count
>
std::function<boost::any(std::vector<boost::any>)> erased_func_t;

template<class... Args, class F>
erased_func_t erase_func(F&& f) {
  // TODO
}