我正在考虑通过指定成对的
{ID, LAMBDA} 来为服务器创建一个dispatcher()
函数以供服务器选择。所有ID都是唯一的。假设我有 send()
和 receive()
函数支持所有允许的类型,您将如何编写一个 dispatcher()
函数来接收 ID,选择相应的 lambda 函数,接收其参数,调用它并发送结果?对于服务器的不同实例,我将有多个 dispatcher()
实例,每个实例具有不同的功能集,并且我不希望在实现中使用 switch 语句。这是此类应用程序的简化框架(编译器资源管理器演示):
#include <utility>
#include <vector>
template<class T>
auto receive() { return -1; } // for exposition only
void send(auto&& ... values);
template<std::pair...functions>
void dispatcher()
{
for(auto function_id = 0; function_id != -1;)
{
function_id = receive<int>();
// select function corresponding to function_id
// receive function arguments
// invoke function and send return value
}
}
int main()
{
dispatcher<{100, []{ return 100;}},
{1000, [](const std::vector<int>& v){ return v; }}>();
}
该解决方案基于以下两个步骤:
首先,我们创建一个折叠表达式(由@Ted Lyngmo 建议) 结果调用与 lambda 对应的
executor()
函数
功能ID。
其次,我们使用lambda函数特征来确定参数类型 需要接收这些参数,将它们传递给 对应的lambda函数并发送执行结果。
以下代码演示了这种方法(编译器资源管理器演示):
template<class Fn> struct lambda_traits;
template< class R, class G, class ... A >
struct lambda_traits<R(G::*)(A...) const>
{
using Args = std::tuple<std::remove_cvref_t<A>...>;
};
template<class Fn>
struct lambda_traits : lambda_traits<decltype(&Fn::operator())>{};
template<class Fn>
using lambda_args = typename lambda_traits<std::remove_cvref_t<Fn>>::Args;
template <std::pair function>
auto executor() {
// receive function arguments for function.first here
std::cout << "Executing function ID " << function.first << '\n';
std::apply([&](auto&&...args)
{
send(std::invoke(function.second,
receive<std::remove_cvref_t<decltype(args)>>()...));
}, lambda_args<decltype(function.second)>{});
}
template<std::pair...functions>
void dispatcher()
{
for(auto function_id : {10, 100})
{
//function_id = receive<int>();
(void)((functions.first == function_id
&&
(executor<functions>(), true)) || ...);
}
}
int main()
{
dispatcher<{100, []{ return 123;}},
{10, [](const std::vector<int>& v){ return v; }}>();
}