gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:24:06 25 4
gpt4 key购买 nike

我有一组使用 std::function 的委托(delegate),它们指向具有不同签名的函数。我希望能够在运行时使用字符串键检索这些委托(delegate)。我似乎无法使用 map ,因为它们指向具有不同签名的函数。我可以在没有 switch 语句的情况下拥有这样的功能吗?

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

E:与所选答案相关的有用链接,需要花费大量时间才能掌握

http://en.cppreference.com/w/cpp/utility/functional/function

http://en.cppreference.com/w/cpp/utility/forward

http://en.cppreference.com/w/cpp/utility/integer_sequence

http://en.cppreference.com/w/cpp/types/result_of

http://en.cppreference.com/w/cpp/types/remove_reference

http://www.boost.org/doc/libs/1_57_0/doc/html/any.html

最佳答案

从类型包开始:

template<class...Ts>struct types{
using type=types;
enum{count = sizeof...(Ts)};
};
template<class T> struct tag{using type=T;};

现在我们在一个全局 types 中定义所有支持的类型捆绑。

索引进入那个全局types bundle 通过网络发送,并用于查找反序列化代码。

应该有一个函数boost::any read( wire_data, T* unused )在你的协议(protocol)命名空间(基本类型和 std 类型)和 T 的命名空间中定义(对于其他类型)将有线数据读入 boost::any . wire_data只是一个占位符,用于表示您从电线上取下的任何东西,然后变成 T .

我们将类型索引转换为对 read 的调用通过魔术开关技术:

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
> {};

给我们一个类型的偏移量 Ttypes<Ts...> .在发送端使用它来将您的类型映射到列表中的索引。

另一方面,我们有:

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>
{};

需要 types<Ts...>和一个索引并返回一个类型。

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 );
}
};
};

发送到 read使用 ADL。

现在我们编写我们的快速魔法开关:

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
>

是无状态函数对象的类型,当传递给 n 时和 wire_data , 将调用适当的 read该类型的函数并返回 boost::any .

好的,现在我们已经完成了一半。

下半部分涉及到我们签名的功能Z(Args...) , 并编写一个带 std::vector<boost::any> 的类型橡皮擦存储 Args...并返回 boost::any存储 Z .

std::function<boost::any(std::vector<boost::any>)> erased_func_t;

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

一旦我们写好了,我们就可以存储一个从字符串到 erased_func_t 的映射。用于我们的函数表。

我们查找 erased_func_t .我们使用上面的反序列化基础设施来生成一个 std::vector<boost::any>从传入的参数。我们调用它,如果失败则抛出异常。

鲍勃是你的叔叔。

如果你想发回答案,你需要输入删除回到有线格式,并更改 erased_func_t返回 wire_data需要通过网络而不是 boost::any 将其发回.这可能是最好的。

以上代码均未经过测试。其中一些需要 C++14(不是那么多,主要是 _t 别名),而一些声称支持 C++11 的编译器不支持 magic_switch我写的实现(它几乎是纯 C++11,除了 _t 别名,我相信)。但是可以写一个等效的,如果更冗长的话。

最后,像许多事情一样,从头开始编写 RPC 协议(protocol)通常不是一个好主意。很可能我错过了上面的一个重要步骤。

关于c++ - 按名称调用不同签名的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28953332/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com