如何将std::vector<boost::optional<double>>转为std::vector<double>?可选元素映射为0
一行代码搞定
boost::optional<double>向量转double向量 当然有更简洁的一行代码解决方案,而且还能修正你原来代码里的小问题——你之前的代码先初始化了out的大小为foo.size(),然后又调用push_back,这会导致out最终的大小是原来的两倍(前面是foo.size()个默认值0,后面才是转换后的元素),这肯定不是你想要的结果。
针对boost::optional的解决方案
如果你的Boost版本足够新(支持boost::optional::value_or方法,一般Boost 1.53及以上就有了),可以用一行代码完成转换:
std::vector<double> out; std::transform(foo.cbegin(), foo.cend(), std::back_inserter(out), [](const auto& opt) { return opt.value_or(0.0); });
如果你的Boost版本比较旧,不支持value_or,就用三元表达式替代:
std::vector<double> out; std::transform(foo.cbegin(), foo.cend(), std::back_inserter(out), [](const auto& opt) { return opt ? *opt : 0.0; });
要是你想把向量的初始化和转换合并成真正的一行(连变量声明都在一行),也可以这么写:
std::vector<double> out(foo.size()); std::transform(foo.cbegin(), foo.cend(), out.begin(), [](const auto& opt) { return opt ? *opt : 0.0; });
这个版本直接预先分配好out的大小,然后用out.begin()作为输出迭代器,避免了back_inserter的开销,效率更高。
针对std::optional的解决方案
如果换成标准库的std::optional,逻辑完全一致,因为std::optional从C++17开始就内置了value_or方法:
std::vector<double> out; std::transform(foo.cbegin(), foo.cend(), std::back_inserter(out), [](const auto& opt) { return opt.value_or(0.0); });
或者同样用预分配大小的版本:
std::vector<double> out(foo.size()); std::transform(foo.cbegin(), foo.cend(), out.begin(), [](const auto& opt) { return opt ? *opt : 0.0; });
更现代的C++20写法(可选)
如果你能用C++20的范围库,可以写得更简洁:
auto out = foo | std::views::transform([](const auto& opt) { return opt.value_or(0.0); }) | std::ranges::to<std::vector<double>>();
这一行直接通过管道操作完成转换,可读性拉满,不过需要编译器支持C++20及以上的范围特性。
内容的提问来源于stack exchange,提问作者Sebastian John Howard
相关产品推荐
相关产品推荐

