我可以毫无例外地使用 std::累积与易错操作吗?
Can I use std::accumulate with a fallible operation without exceptions?
我有一些操作,我想与 std::accumulate 一起使用,但它可能会对某些元素失败,在这种情况下,累积应该中止。在例外情况下,我可以在失败时抛出异常,但我需要在无异常的情况下进行构建。除了例外,这看起来像这样(操作大大简化(:
std::optional<int> sum_accumulate_with_exceptions(
std::vector<int> const& aVec) {
try {
return std::accumulate(aVec.begin(), aVec.end(), 0,
[](int oldSum, int current) {
if (current > 42)
throw std::logic_error{"too large"};
return oldSum + current;
});
} catch (std::logic_error const&) {
return std::nullopt;
}
}
实际上,即使有可能使用异常,这似乎也很浪费,因为我对抛出的特定异常不感兴趣,因此异常的开销不必要地大。
使用 std::accumulate,我可以使用这样的错误标志:
std::optional<int> sum_accumulate_without_exceptions(
std::vector<int> const& aVec) {
bool errored = false;
int res = std::accumulate(aVec.begin(), aVec.end(), 0,
[&errored](int oldSum, int current) {
if (errored) return 0;
if (current > 42) {
errored = true;
return 0;
}
return oldSum + current;
});
return errored ? std::optional<int>{} : res;
}
但是,这显然是不好的,因为这总是遍历整个容器,这可能很大。
我想出了我自己的 std::累积变体:
template <typename It, typename T, typename Op>
std::optional<T> accumulate_shortcircuit(It aBegin, It aEnd, T aInit,
const Op& aOp) {
std::optional<T> res = std::move(aInit);
for (auto it = aBegin; it != aEnd; ++it) {
res = aOp(*res, *it);
if (!res) break;
}
return res;
}
这可以很好地用于以下示例案例,如下所示:
std::optional<int> sum_accumulate_shortcircuit(std::vector<int> const& aVec) {
return accumulate_shortcircuit(aVec.begin(), aVec.end(), 0,
[](int oldSum, int current) {
if (current > 42) {
return std::optional<int>{};
}
return std::optional<int>{oldSum + current};
});
}
但是,我更喜欢使用 std::accumulate(或任何其他标准库算法 [edit:] 或它们的组合(本身,而不是使用替换。有什么办法可以做到这一点吗?
当我在示例中使用 C++17 的 std::optional 时,理想情况下,这将只使用 C++14 个标准库算法,但我也对更新/未来标准版本的解决方案感兴趣。
[编辑:] 根据@NathanOliver的回答,accumulate_shortcircuit可以这样实现,而没有范围 TS:
template <typename It, typename T, typename Op>
std::optional<T> accumulate_shortcircuit(It aBegin, It aEnd, T aInit,
const Op& aOp) {
std::optional<T> res = std::move(aInit);
std::all_of(aBegin, aEnd, [&](const T& element) {
return static_cast<bool>(res = aOp(*res, element));
});
return res;
}
您需要一种内置短路的算法。 首先想到的是std::any_of
. 您可以使用 lambda 进行求和,然后在达到要返回的点后返回 true。 那会给你一个像
int sum_accumulate_shortcircuit(std::vector<int> const& aVec)
{
int sum = 0;
std::any_of(aVec.begin(), aVec.end(),
[&](auto elm) { if (elm > 42) return true; sum += elm; return false; });
return sum;
}
为了将来参考,这种类型的算法/操作组合在 C++20 中会容易得多(包含范围 TS(。这是当前 TS 使用accumulate
和view::take_while
的示例:
auto sum = ranges::accumulate(my_vec | view::take_while([] (auto i) -> i <= 42), 0);
相关文章:
- #定义c-预处理器常量..我做错了什么
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 努力将整数转换为链表。不知道我在这里做错了什么
- 重载操作程序时出错>>用于类中的字符串 memebr
- 首要问题的答案让值班员搞错了
- 对字符串进行位操作
- 我可以在 C++ 中的函数体之外进行操作吗?
- MPI突然停止了对多个核心的操作
- 看起来is_nothrow_constructible_v()在MSVC中被破坏了,我错了吗
- 如何在信号处理程序和普通函数中对全局变量进行互斥读写操作
- 对字符数组中的元素执行逐位操作
- 如何在directx/c++中进行平移/缩放操作
- 逐位操作的隐式类型转换
- 为什么一个向量上的多线程操作很慢
- 排序时无法执行交换操作.我做的时候它会崩溃.为什么
- .h 和.cpp文件分离时出错,但仅使用 .h 文件时没有错误.我做错了什么?
- 位移操作和位掩码未检测到重复字符
- 如何进行特定的位操作?
- 我可以毫无例外地使用 std::累积与易错操作吗?
- 具有易失性原子变量的原子操作