c++ - 现代 C++ - 如何使用 std::optional 和引用实现 FirstOrDefault
问题描述
在使用 C# 和 Javascript/Typescript 多年后,我再次选择了 C++。我已经非常习惯编写使用算法来操作和查询容器的代码,例如:
C#
var mocData = Enumerable.Range(0, 100)
.Where(n => n % 2 == 1)
.Select(n => new Item(n))
.ToList();
Javascript(使用 Lodash <3 )
const mocData = _.chain(_.range(0, 100))
.filter(n => n % 2 == 1)
.map(n => ({ n: `Item #${n}` }))
.value();
现在,C++ 是一个非常不同的野兽,我正在尝试做的事情,但没有取得多大成功(从简洁的语法/低冗长的角度来看),是为 STL 的函数编写一个包装器,允许我处理容器内的项目,而不是它们的副本,使用值语义,同时还考虑了“可空性(即 std::optional 包装值)。例如,如果您不关心可空性,则查找函数很容易编写。这就是我的方法想使用它,以及它是如何实现的:
template<typename T, typename Predicate>
auto find(const std::vector<T>& items, Predicate pred) -> T& {
auto it = std::find_if(items.begin(), items.end(), pred);
if (it == items.end()) {
throw std::runtime_error{ "Sequence contains no matching elements." };
}
return *it;
}
std::vector<MyClass> items = { ... };
const auto& item = find(items, [](const MyClass& o) { return o... });
++item.count; // Modifies the item inside of the container
现在,如果我想考虑可空性,如在 C# 或 javascript 中:
C#
var item = items.FirstOrDefault(o => o...);
item?.DoSomething();
Javascript
const item = _.find(items, o => o...);
item?.doSomething();
我必须在 C++ 中使用 std::optional 。并且为了避免复制(以便能够修改容器中的项目!!),我必须返回 std::optional。但是 std::optional 不能直接与 T& 一起使用,所以我必须使用 std::reference_wrapper 作为它的类型:
template<typename T>
using Ref = std::reference_wrapper<T>;
template<typename T, typename Predicate>
auto firstOrDefault(std::vector<T>& vec, Predicate pred) -> std::optional<Ref<T>> {
auto it = std::find_if(vec.begin(), vec.end(), pred);
if (it == vec.end()) {
return std::nullopt;
}
return std::ref(*it);
}
现在,丑陋的部分是使用返回值:
const auto item = firstOrDefault(items, predicate...);
if (item.has_value()) {
item
.value() // unwrap the ref from std::optional
.get() // unwrap T& from std::reference_wrapper<T>
.do_something() // jeeeez so hard to use it!!
}
我知道我可以使用指针,并且使用非拥有指针作为引用并没有什么不好,也许使用 C++ 核心指南的类型......但是引用是为了维护值语义,我想使用它们即使它们不能很好地使用 STL 中的容器和包装器。
有没有好的方法来实现这一目标?
编辑:我已经修改了标题以更好地表达我不想要一个类似 LINQ 的库,我试图了解现代 C++20 是否可以使用可空性和引用(不是指针)体面的语法。
解决方案
推荐阅读
- symfony4 - 多对一关系 symfony4
- javascript - 元素不遵循过滤器 CSS 的语义
- android - 如何获得预定义的振动模式?
- java - 是否可以从 .class 文件中获取注释的行号?
- c# - 将 android 应用程序构建为一个独立的单元(用于 PC),同时保持正确的纵横比
- .net - (TTFB) 某些特定请求的执行时间比执行实际请求的时间要长
- python - 带有额外字段的 DRF 多态多对多
- java - Java 可选:检查几个备选方案(代码更优雅)
- javascript - 如何将 HTML 表格数据插入数据库
- c# - 如何更新 SharePoint 目录中的“列表项”