让我来描述一个场景,首先我们有一个函数,它返回一些我们不能确定其有效性的数据,即。
auto random_predicate() -> bool
{
int v = uniform_dist(e1); // uniform distribution 1 to 100
return (v % 5);
}
其中uniform_dist()
是适当播种的均匀分布,并且我们具有将用于错误处理的enum class
,即
enum class Error
{
ValueError
};
然后,我们执行某种基于视图的处理,该处理在操作中使用random_predicate()
,如下所示:
std::vector<int> vs{1,2,3,4,5};
auto result = vs
| views::filter([](int i){ return i % 2; })
| views::transform([](int i) -> std::expected<int, Error> {
auto v = random_predicate();
if (v) return std::unexpected<Error>(Error::ValueError);
else return i * i;
});
所以,在这个运算结束时,我们可以Assert
static_assert(
std::is_same_v<
std::decay_t<std::ranges::range_value_t<result>>,
std::expected<int, Error>
>
)
都是真的。
问题是,然后呢?我们知道有一个std::expected
值的视图,我们需要将其解析为:沿调用堆栈向上传播的错误类型,或成功类型的视图(即,上例中的int
视图(所有元素都不是5的倍数!))
∮我的解决方案∮
我的解决方案是简单地检查每个元素是否有错误,如果没有错误,则将结果转换为所需的视图,类似于
template<typename T>
static auto has_error(const std::expected<T, Error>& e){ return !e.has_value(); };
auto f(const std::vector<int>& vs)
{
auto c = vs
| views::filter([](int i){ return i % 2; })
| views::transform([](int i) -> std::expected<int, Error> {
auto v = random_predicate();
if (v) return std::unexpected<Error>(Error::ValueError);
else return i * i;
});
if (auto v = ranges::find_if(c, has_error<int>); v != c.end())
{
return (*v).error();
}
else
{
return c | views::transform([](auto&& e){ return e.value(); });
}
}
但是接下来我们遇到了一个问题,函数不能推导出返回类型为std::expected<T, Error>
,其中T
是一个容器的类型,该容器包含类型为int
的元素(在上面的例子中),我甚至不知道在这里为T
写什么,所以我的问题是应该如何实现它?
神箭:https://godbolt.org/z/Wfjr8o3qM
或者,我感兴趣的是听听其他人如何一起以更好的方式处理这个问题?
谢谢
编辑:我想,你并不真的想返回一些元素的视图,因为这可能会导致一个悬空视图?在这种情况下,当从函数返回时,最好只使用ranges::to<T>()
吗?
2条答案
按热度按时间pgvzfuti1#
为了确定函数
f
的适当返回类型,可以使用std::ranges::range_value_t
和std::ranges::range_reference_t
类型特征,以及std::conditional_t
类型特征。首先,可以使用
std::ranges::range_value_t<decltype(c)>
获取基于视图的处理返回的范围的值类型,应该是std::expected<int, Error>
。然后,您可以使用
std::ranges::range_reference_t<decltype(c)>
来获取范围的引用类型,如果范围是可变的,则应为std::expected<int, Error>&
,如果范围是常量,则应为const std::expected<int, Error>&
。最后,你可以使用
std::conditional_t
来有条件地选择返回类型,这是一个f
的示例实现,它利用了这些类型特征:在此实现中,根据范围内是否存在错误来选择返回类型,使用
std::ranges::any_of
。如果存在错误,则返回类型为error_type
(相当于std::expected<value_type, Error>::error_type)
。否则,返回类型是成功类型(value_type
)的std::vector
。请注意,views::transform operation
用于在转换为std::vector
之前将std::expected
值的范围转换为成功值的范围。jv4diomz2#
仍然能够返回范围的另一个选项:
它利用了这样一个事实,即视图的值是惰性计算的,因此如果它没有返回,值将永远不会被计算,我们可以使用它来确定返回类型。下一步是确保所有返回都被 Package 到
ret_t
类型中,以便auto可以正确猜测。注意:无论是在这个答案还是你原来的问题中,这个只能在原来的范围内工作,可以迭代多次(不记得这个概念的名字了对不起)