c++ - lambda 参数的模板推导
问题描述
我目前有许多数据访问器,例如:
template <typename Fn>
typename std::result_of<Fn(DataA)>::type GetDataA(Fn fn) {
DataA a = DoSomeWorkToGetA();
return fn(a);
}
template <typename Fn>
typename std::result_of<Fn(DataB)>::type GetDataB(Fn fn) {
DataB b = DoSomeWorkToGetB();
return fn(b);
}
使用如下:
auto computation_result_a = GetDataA([](DataA a) {
return DoCustomProcessingOnA(a);
});
auto computation_result_b = GetDataB([](DataB a) {
return DoCustomProcessingOnB(b);
});
我想要的是一种自动生成这些 Getter 组合的方法,例如:
template <typename Fn>
typename std::result_of<Fn(DataA, DataB)>::type GetDataAandB(Fn fn) {
DataA a = GetDataA([](DataA a) { return a; });
DataB b = GetDataB([](DataB b) { return b; });
return fn(a, b);
}
我在过去看到过这种类型的事情,用户 API 如下:
auto computation_result_a = GetData<A>([](Data a) { /**/ });
auto computation_result_b = GetData<A>([](Data b) { /**/ });
auto computation_result_ab = GetData<A,B>([](Data a, Data b) { /**/ });
但我不确定如何做到这一点。
解决方案
首先,您需要从类型(或标签)到正确DoSomeWorkToGet*
功能的映射,例如:
template<typename T> /* or an enum instead of typename */
void DoSomeWorkToGet() = delete;
template<>
auto DoSomeWorkToGet<A>() { return DoSomeWorkToGetA(); }
template<>
auto DoSomeWorkToGet<B>() { return DoSomeWorkToGetB(); }
然后编写函数只是使用可变参数模板和包扩展的问题:
template<typename... Ts, typename F> /* or an enum instead of the first typename */
auto GetData(F f) {
return f(DoSomeWorkToGet<Ts>()...);
}
用作例如:
auto computation_result_ab = GetData<A, B>([](auto a, auto b) {
return /* something with a and b */;
});
如果您需要DoSomeWorkToGet
按从左到右的顺序评估函数,则不能使用上述函数,但可以使用以下函数:
template<typename... Ts, typename F> /* or an enum instead of the first typename */
auto GetData(F f) {
using tuple_type = std::tuple<decltype(DoSomeWorkToGet<Ts>())&&...>;
return std::apply(f, tuple_type{DoSomeWorkToGet<Ts>()...});
}
这需要 C++17。也可以使用 C++11/C++14 实现,但需要做更多的工作(实现std::apply
或更弱的形式)。它保证了评估顺序,因为列表初始化(在 中使用tuple_type{...}
)始终严格按照从左到右的顺序排列。
推荐阅读
- r - 具有特定高度的渲染图不允许下一个显示表格(闪亮)
- javascript - 带有多个变量的 Javascript/Jquery 切换 id
- angular - Angular 电子邮件验证模式
- java - 一个人如何在 Java 中从 MusicXML 中绘制乐谱?
- kubernetes - 如何在气流 kuber pod 操作员中设置 dns 配置?
- typescript - 从嵌套对象的特定属性中获取联合类型
- c++ - 嵌套的结构数组 - 我如何正确地为结构成员赋值?
- linux - 使用 shell 命令替换随机字符串的开始和结束
- javascript - 如何在 html/css/js 中禁用页面滚动?
- flutter - “int”类型不是“List”类型的子类型
'