我想要查看输入流中的字符:
auto input = std::stringstream{"abcd"};
using Iter = std::istreambuf_iterator<char>;
auto s = std::ranges::subrange{Iter{input}, Iter{}};
到目前为止一切顺利。现在,我转换该视图(为了简单起见,使用身份转换):
auto t = s | std::views::transform(std::identity{});
尽管这个转换后的观点是有效的value_type
(即这个断言通过了):
using T = decltype(t);
static_assert(std::is_same_v<char, std::ranges::range_value_t<T>>);
它的迭代器类型没有:
static_assert(std::is_same_v<char, std::iterator_traits<std::ranges::iterator_t<T>>::value_type>);
这失败了
view.cc: In function 'int main()':
view.cc:27:90: error: 'value_type' is not a member of 'std::iterator_traits<std::ranges::transform_view<std::ranges::subrange<std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> >, std::ranges::subrange_kind::unsized>, std::identity>::_Iterator<false> >'
27 | static_assert(std::is_same_v<char, std::iterator_traits<std::ranges::iterator_t<T>>::value_type>);
| ^~~~~~~~~~
view.cc:27:100: error: template argument 2 is invalid
27 | static_assert(std::is_same_v<char, std::iterator_traits<std::ranges::iterator_t<T>>::value_type>);
|
它对我很重要的原因是我想在下游视图适配器中使用迭代器特征。
调查表明,Transform 视图的迭代器缺少其iterator_category
成员。当我传递一个功能更强大的范围(例如,传递给 Transform 的范围)时,代码会成功,std::string
但传递这个非前向范围时会失败。
完整代码(也在Compiler Explorer 上):
#include <functional>
#include <iterator>
#include <ranges>
#include <sstream>
#include <string>
#include <type_traits>
int main()
{
#ifdef PASS
auto input = std::string{"abcd"};
std::ranges::forward_range auto s = std::ranges::subrange(input.begin(), input.end());
#else
auto input = std::stringstream{"abcd"};
using Iter = std::istreambuf_iterator<char>;
std::ranges::input_range auto s = std::ranges::subrange{Iter{input}, Iter{}};
#endif
using S = decltype(s);
static_assert(std::is_same_v<char, std::ranges::range_value_t<S>>);
static_assert(std::is_same_v<char, std::iterator_traits<std::ranges::iterator_t<S>>::value_type>);
auto t = s | std::views::transform(std::identity{});
using T = decltype(t);
static_assert(std::is_same_v<char, std::ranges::range_value_t<T>>);
static_assert(std::is_same_v<char, std::ranges::iterator_t<T>::value_type>);
static_assert(std::is_base_of_v<std::input_iterator_tag, std::ranges::iterator_t<T>::iterator_category>);
static_assert(std::is_same_v<char, std::iterator_traits<std::ranges::iterator_t<T>>::value_type>);
}