如何解决如何将istream_view收集到容器中?
我正在尝试对c++20的ranges
的扩展实施通用的归约运算,以将任何range
的元素收集到给定的容器中。为此,我首先创建了一个用于提取template template
参数的伪类型,并提供了operator|
用于将range
与其组合:
template <template <typename> typename T>
struct to_fn { };
template <template <typename> typename T>
inline constexpr detail::functors::to_fn<T> to;
template <template <typename> typename T>
auto operator|(std::ranges::range auto&& rng,detail::functors::to_fn<T>) {
return T(std::ranges::begin(rng),std::ranges::end(rng));
}
经过如下测试:
int main() {
using namespace std::ranges;
std::vector<int> vec = {1,2,3,4,5};
auto set = vec | to<std::set>;
static_assert(std::same_as<decltype(set),std::set<int>>);
assert(equal(vec,set));
}
代码完成执行没有问题。
但是,与std::ranges::istream_view
一起使用时,代码无法编译:
int main() {
using namespace std::ranges;
std::ifstream input_file("input.txt");
auto vec = istream_view<int>(input_file) | to<std::vector>;
}
此无法编译时会出现一堆错误,我认为其中重要的一点是:
note: deduced conflicting types for parameter '_InputIterator' ('std::ranges::basic_istream_view<int,char,std::char_traits<char> >::_Iterator' and 'std::default_sentinel_t') 122 | return T(std::ranges::begin(rng),std::ranges::end(rng)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这对我来说很有意义。容器要求用于通过构造函数构造它们的迭代器(其中两个是相同类型)。
但这很好-这就是创建std::ranges::views::common_view
的目的。所以我尝试将operator|
修改为:
template <template <typename> typename T>
auto operator|(std::ranges::range auto&& rng,detail::functors::to_fn<T>) {
auto common = rng | std::ranges::views::common;
return T(std::ranges::begin(common),std::ranges::end(common));
}
再次失败,并且编译时出现的错误墙较小,其中我认为这是最相关的:
note: the expression 'is_constructible_v<_Tp,_Args ...> [with _Tp = std::ranges::basic_istream_view<int,std::char_traits<char> >::_Iterator<int,std::char_traits<char> >; _Args = {std::ranges::basic_istream_view<int,std::char_traits<char> >&}]' evaluated to 'false' 139 | = destructible<_Tp> && is_constructible_v<_Tp,_Args...>; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
我不太理解该错误所指示的内容,但是我想这意味着istream_view
无法进行复制构造。对我来说有点道理。
但是我真的希望我可以拥有这个通用的to
“ functor”。我认为推断出我们正在处理输入时,可以使用基于基于范围的istream_view
遍历for
并将元素添加到所选容器中是可以的范围 1 。
所以我尝试了这个:
template <template <typename> typename T>
auto operator|(std::ranges::range auto&& rng,detail::functors::to_fn<T>) {
using namespace std::ranges;
using range_t = decltype(rng);
const bool input_range = std::is_same_v<
iterator_t<range_t>::iterator_category,std::input_iterator_tag>;
if constexpr(input_range) {
auto container = T<range_value_t<range_t>>();
for (auto&& element : rng) {
container.generic_add(element); // ???
}
return container;
} else {
auto common = rng | views::common;
return T(begin(common),end(common));
}
}
接着,他告诉我:
error: 'iterator_category' is not a member of 'std::ranges::iterator_t<std::ranges::basic_istream_view<int,std::char_traits<char> >&&>' 125 | iterator_t<range_t>::iterator_category,| ^~~~~~~~~~~~~~~~~
这不是唯一的问题。还存在将元素一般添加到任何容器的问题。据我所知,采用range
的构造函数是向容器添加元素的唯一通用方法和 good 方法。
我觉得必须有一种正确,简单的方法来做我想做的事情。如果to
也适用于非模板,则奖励积分,即我不仅可以to<std::vector>
,而且可以to<std::string>
。在第一种情况下,它将推导元素并创建所需的std::vector
实例化,但是在第二种情况下,它将获取所有元素并用这些元素初始化std::string
。我该如何工作?
1 假设实际问题出在我们正在使用输入范围的事实。我不确定是否是这种情况。如果有人可以指出我的推理中可能存在的错误,我将很乐意。
解决方法
这假设实际问题出在我们正在使用输入范围的事实中。
问题不在于它是一个输入范围,而是std::ranges::istream_view<int>
及其迭代器类型仅可移动。
在C ++ 17中,所有迭代器都必须是可复制的。在C ++ 20中放宽了该限制,现在我们可以拥有仅移动的迭代器和仅移动的视图。但是必须更改代码以支持-std::vector
的迭代器对构造函数仍基于C ++ 17迭代器模型,该模型确实会复制迭代器,因此它不适用于std::ranges::istream_view<int>::iterator
。 / p>
common_view
的重点是采用C ++ 20范围,该范围的哨兵类型不同于其迭代器类型,并通过产生相同的类型使其适应C ++ 17算法对于迭代器和哨兵。但是这里的重点是要使用C ++ 17算法,因此它必须遵守C ++ 17迭代器要求。这些要求包括可复制性,因此[range.common.view]中的common_view
被声明为:
namespace std::ranges {
template<view V>
requires (!common_range<V> && copyable<iterator_t<V>>)
class common_view : public view_interface<common_view<V>> {
这就是rng | views::common
不能为您编译的原因,common
需要可复制性(在迭代器/前哨类型不同的情况下,如此处所做的那样),而您却没有(可复制)您应该转发rng
,因为即使views::common
不需要直接复制,您所做的实际上是在复制它,因此将分别失败。)
实际上没有任何方法可以适配std::ranges::istream_view<int>
以便可以使用vector<int>
的迭代器对构造器。我们可能需要以某种方式更改vector
才能使此构造正常工作(现在肯定对您没有帮助),或者您必须通过执行以下操作来处理这种情况:
std::vector<int> v;
for (int e : rng) {
v.push_back(e);
}
return v;
在s.insert(e)
情况下,看上去必须像std::set
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。