自定义范围适配器仅在合成结束时有效
Custom range adaptor only works at the end of composition
我正在构建一个自定义范围适配器,我称之为 replicate_view
,它应该 return 视图的每个元素 N
次。这是一个例子:
for (auto i : std::views::iota(1, 5) |
views::replicate(2))
std::cout << i << '\n';
这应该打印:1 1 2 2 3 3 4 4
但是,如果我在它后面添加一些东西,它不起作用:
for (auto i : std::views::iota(1, 5) |
views::replicate(2) |
std::views::take(2))
std::cout << i << '\n';
这给出了错误。
VC++:
error C2678: binary '|': no operator found which takes a left-hand operand of type 'n805::replicate_view<std::ranges::iota_view<_Ty1,_Ty2>>' (or there is no acceptable conversion)
叮当声:
error: invalid operands to binary expression ('replicate_view<std::ranges::views::all_t<iota_view<int, int>>>' (aka 'replicate_view<std::ranges::iota_view<int, int>>') and 'std::__range_adaptor_closure_t<std::__bind_back_t<std::ranges::views::__take::__fn, std::tuple<int>>>')
这是我的实现。
迭代器和哨兵
template <typename R>
struct replicate_iterator;
template <typename R>
struct replicate_sentinel
{
using base = std::ranges::iterator_t<R>;
using size_type = std::ranges::range_difference_t<R>;
constexpr replicate_sentinel(base end) : end_{ end } {}
constexpr bool is_at_end(replicate_iterator<R> it);
private:
base end_;
};
template <typename R>
struct replicate_iterator : std::ranges::iterator_t<R>
{
using base = std::ranges::iterator_t<R>;
using value_type = typename std::ranges::range_value_t<R>;
constexpr replicate_iterator(base start, std::ranges::range_difference_t<R> count) :
pos_{ start }, count_{ count }
{
}
constexpr replicate_iterator operator++(int)
{
if (step_ == count_)
{
step_ = 1;
pos_++;
}
else
{
step_++;
}
return pos_;
}
constexpr replicate_iterator& operator++()
{
if (step_ == count_)
{
step_ = 1;
pos_++;
}
else
{
step_++;
}
return (*this);
}
constexpr value_type operator*() const
{
return *pos_;
}
constexpr bool operator==(replicate_sentinel<R> s)
{
return s.is_at_end(*this);
}
constexpr base const value() const { return pos_; }
private:
base pos_;
std::ranges::range_difference_t<R> count_;
std::ranges::range_difference_t<R> step_ = 1;
};
template <typename R>
constexpr bool replicate_sentinel<R>::is_at_end(replicate_iterator<R> it)
{
return end_ == it.value();
}
量程适配器
template<std::ranges::view R>
struct replicate_view : public std::ranges::view_interface<replicate_view<R>>
{
private:
R base_;
std::ranges::range_difference_t<R> count_;
public:
replicate_view() = default;
constexpr replicate_view(R base, std::ranges::range_difference_t<R> count)
: base_(std::move(base))
, count_(count)
{
}
constexpr R base() const&
requires std::copy_constructible<R>
{ return base_; }
constexpr R base()&& { return std::move(base_); }
constexpr std::ranges::range_difference_t<R> const& increment() const { return count_; }
constexpr auto begin() const
{
return replicate_iterator<R>(std::ranges::begin(base_), count_);
}
constexpr auto end() const
{
return replicate_sentinel<R>{std::ranges::end(base_)};
}
constexpr auto size() const requires std::ranges::sized_range<R>
{ return count_ * std::ranges::size(base_); }
constexpr auto size() requires std::ranges::sized_range<R>
{ return count_ * std::ranges::size(base_); }
};
推导指南
template<class R>
replicate_view(R&& base, std::ranges::range_difference_t<R> count)
->replicate_view<std::ranges::views::all_t<R>>;
范围适配器对象
namespace details
{
struct replicate_view_fn_closure
{
std::size_t step_;
constexpr replicate_view_fn_closure(std::size_t step)
: step_(step)
{
}
template <std::ranges::sized_range R>
constexpr auto operator()(R&& r) const
{
return replicate_view(std::forward<R>(r), step_);
}
};
struct replicate_view_fn
{
template<std::ranges::sized_range R>
constexpr auto operator () (R&& r, std::size_t step) const
{
return replicate_view(std::forward<R>(r), step);
}
constexpr auto operator () (std::size_t step) const
{
return replicate_view_fn_closure(step);
}
};
template <std::ranges::sized_range R>
constexpr auto operator | (R&& r, replicate_view_fn_closure&& a)
{
return std::forward<replicate_view_fn_closure>(a)(std::forward<R>(r));
}
}
namespace views
{
inline constexpr details::replicate_view_fn replicate;
}
范围适配器类型有:
- 默认构造函数
base()
会员
size()
会员
迭代器类型有:
base
类型成员
value_type
类型成员
这是一个演示:https://godbolt.org/z/fM5dz5zzf
我不知道缺少了什么。
首先,sentinel_for
要求sentinel必须是default_initializable
,所以需要为replicate_sentinel
添加默认构造函数。
template <typename R>
struct replicate_sentinel
{
replicate_sentinel() = default;
// ...
};
其次,sentinel_for
还要求const iterator&
与const sentinel&
相媲美,所以replicate_iterator::operator==
应该是const
合格的(我怀疑这只是打字错误)
template <typename R>
struct replicate_iterator : std::ranges::iterator_t<R>
{
constexpr bool operator==(replicate_sentinel<R> s) const
{
return s.is_at_end(*this);
}
// ...
};
来自巴里:
The way to check this kind of thing for ranges is:
- Verify that your iterator is an
input_iterator
.
- Verify that your
sentinel is a
sentinel_for
your iterator.
Those are the checks that
will tell you what functionality you're missing.
我正在构建一个自定义范围适配器,我称之为 replicate_view
,它应该 return 视图的每个元素 N
次。这是一个例子:
for (auto i : std::views::iota(1, 5) |
views::replicate(2))
std::cout << i << '\n';
这应该打印:1 1 2 2 3 3 4 4
但是,如果我在它后面添加一些东西,它不起作用:
for (auto i : std::views::iota(1, 5) |
views::replicate(2) |
std::views::take(2))
std::cout << i << '\n';
这给出了错误。
VC++:
error C2678: binary '|': no operator found which takes a left-hand operand of type 'n805::replicate_view<std::ranges::iota_view<_Ty1,_Ty2>>' (or there is no acceptable conversion)
叮当声:
error: invalid operands to binary expression ('replicate_view<std::ranges::views::all_t<iota_view<int, int>>>' (aka 'replicate_view<std::ranges::iota_view<int, int>>') and 'std::__range_adaptor_closure_t<std::__bind_back_t<std::ranges::views::__take::__fn, std::tuple<int>>>')
这是我的实现。
迭代器和哨兵
template <typename R>
struct replicate_iterator;
template <typename R>
struct replicate_sentinel
{
using base = std::ranges::iterator_t<R>;
using size_type = std::ranges::range_difference_t<R>;
constexpr replicate_sentinel(base end) : end_{ end } {}
constexpr bool is_at_end(replicate_iterator<R> it);
private:
base end_;
};
template <typename R>
struct replicate_iterator : std::ranges::iterator_t<R>
{
using base = std::ranges::iterator_t<R>;
using value_type = typename std::ranges::range_value_t<R>;
constexpr replicate_iterator(base start, std::ranges::range_difference_t<R> count) :
pos_{ start }, count_{ count }
{
}
constexpr replicate_iterator operator++(int)
{
if (step_ == count_)
{
step_ = 1;
pos_++;
}
else
{
step_++;
}
return pos_;
}
constexpr replicate_iterator& operator++()
{
if (step_ == count_)
{
step_ = 1;
pos_++;
}
else
{
step_++;
}
return (*this);
}
constexpr value_type operator*() const
{
return *pos_;
}
constexpr bool operator==(replicate_sentinel<R> s)
{
return s.is_at_end(*this);
}
constexpr base const value() const { return pos_; }
private:
base pos_;
std::ranges::range_difference_t<R> count_;
std::ranges::range_difference_t<R> step_ = 1;
};
template <typename R>
constexpr bool replicate_sentinel<R>::is_at_end(replicate_iterator<R> it)
{
return end_ == it.value();
}
量程适配器
template<std::ranges::view R>
struct replicate_view : public std::ranges::view_interface<replicate_view<R>>
{
private:
R base_;
std::ranges::range_difference_t<R> count_;
public:
replicate_view() = default;
constexpr replicate_view(R base, std::ranges::range_difference_t<R> count)
: base_(std::move(base))
, count_(count)
{
}
constexpr R base() const&
requires std::copy_constructible<R>
{ return base_; }
constexpr R base()&& { return std::move(base_); }
constexpr std::ranges::range_difference_t<R> const& increment() const { return count_; }
constexpr auto begin() const
{
return replicate_iterator<R>(std::ranges::begin(base_), count_);
}
constexpr auto end() const
{
return replicate_sentinel<R>{std::ranges::end(base_)};
}
constexpr auto size() const requires std::ranges::sized_range<R>
{ return count_ * std::ranges::size(base_); }
constexpr auto size() requires std::ranges::sized_range<R>
{ return count_ * std::ranges::size(base_); }
};
推导指南
template<class R>
replicate_view(R&& base, std::ranges::range_difference_t<R> count)
->replicate_view<std::ranges::views::all_t<R>>;
范围适配器对象
namespace details
{
struct replicate_view_fn_closure
{
std::size_t step_;
constexpr replicate_view_fn_closure(std::size_t step)
: step_(step)
{
}
template <std::ranges::sized_range R>
constexpr auto operator()(R&& r) const
{
return replicate_view(std::forward<R>(r), step_);
}
};
struct replicate_view_fn
{
template<std::ranges::sized_range R>
constexpr auto operator () (R&& r, std::size_t step) const
{
return replicate_view(std::forward<R>(r), step);
}
constexpr auto operator () (std::size_t step) const
{
return replicate_view_fn_closure(step);
}
};
template <std::ranges::sized_range R>
constexpr auto operator | (R&& r, replicate_view_fn_closure&& a)
{
return std::forward<replicate_view_fn_closure>(a)(std::forward<R>(r));
}
}
namespace views
{
inline constexpr details::replicate_view_fn replicate;
}
范围适配器类型有:
- 默认构造函数
base()
会员size()
会员
迭代器类型有:
base
类型成员value_type
类型成员
这是一个演示:https://godbolt.org/z/fM5dz5zzf
我不知道缺少了什么。
首先,sentinel_for
要求sentinel必须是default_initializable
,所以需要为replicate_sentinel
添加默认构造函数。
template <typename R>
struct replicate_sentinel
{
replicate_sentinel() = default;
// ...
};
其次,sentinel_for
还要求const iterator&
与const sentinel&
相媲美,所以replicate_iterator::operator==
应该是const
合格的(我怀疑这只是打字错误)
template <typename R>
struct replicate_iterator : std::ranges::iterator_t<R>
{
constexpr bool operator==(replicate_sentinel<R> s) const
{
return s.is_at_end(*this);
}
// ...
};
The way to check this kind of thing for ranges is:
- Verify that your iterator is an
input_iterator
.- Verify that your sentinel is a
sentinel_for
your iterator.Those are the checks that will tell you what functionality you're missing.