无法获得等效的 std::less 来用于嵌套迭代器
Can't get an equivalent to std::less to work for nested iterators
我正在尝试编写一个嵌套迭代器模板。因此,这个想法是,您可以迭代std::array<std::array<int, N> M>>
的int
,就好像它是一个连续数组一样。但是该模板也可以与各种其他组合一起使用。
这是我代码的简化版本,现在有一个小问题:
#include <array>
#include <type_traits>
#include <optional>
template <typename T>
struct default_range {
constexpr auto begin(const T& t) const {
return t.begin();
}
constexpr auto end(const T& t) const {
return t.end();
}
constexpr auto begin(T& t) const {
return t.begin();
}
constexpr auto end(T& t) const {
return t.end();
}
};
template <typename Outer, typename OuterRange>
constexpr auto inner_impl() {
// IMPORTANT: this line is necessary because otherwise OuterRange will always be invoked with the const& version of
// begin().
// Outer must first be captured in a variable so that we preserve constness properly
Outer outer = std::declval<Outer>();
return *std::declval<OuterRange>().begin(outer);
}
template <typename Outer, typename OuterRange>
using inner_t = std::remove_reference_t<decltype(inner_impl<Outer, OuterRange>())>;
template <typename T>
using iterator_value_t = typename std::iterator_traits<T>::value_type;
template <typename OuterIterator,
typename InnerRange = default_range<std::remove_reference_t<iterator_value_t<OuterIterator>>>>
class nested_iterator {
private:
using InnerIterator = decltype (std::declval<InnerRange>().begin(*std::declval<OuterIterator>()));
public:
using self_type = nested_iterator;
using value_type = iterator_value_t<InnerIterator>;
using reference = std::remove_reference_t<value_type> &;
using pointer = std::remove_reference_t<value_type> *;
using iterator_category = std::forward_iterator_tag;
using difference_type = size_t;
private:
struct inner_iterators {
InnerIterator pos;
InnerIterator end;
constexpr inner_iterators(InnerIterator pos, InnerIterator end)
: pos{std::move(pos)}, end{std::move(end)}
{
}
};
OuterIterator outerPos;
OuterIterator outerEnd;
std::optional<inner_iterators> inners = std::nullopt;
InnerRange innerRange;
public:
constexpr nested_iterator(OuterIterator outer, OuterIterator outerEnd)
: outerPos{std::move(outer)}, outerEnd{std::move(outerEnd)}
{
// constructor code here
}
// operator overloads here
}; // class iterator
template <typename Outer,
typename OuterRange = default_range<Outer>,
typename InnerRange = default_range<inner_t<Outer, OuterRange>>>
class nested_iterable {
private:
using Inner = inner_t<Outer, OuterRange>;
public:
using outer_iterator = decltype (std::declval<OuterRange>().begin(std::declval<Outer>()));
using inner_iterator = decltype (std::declval<InnerRange>().begin(std::declval<Inner>()));
using iterator = nested_iterator<outer_iterator, InnerRange>;
private:
Outer *outer;
OuterRange outerRange;
public:
constexpr nested_iterable(Outer &outer) : outer{&outer} {}
constexpr iterator begin() const
{
return {outerRange.begin(*outer), outerRange.end(*outer)};
}
constexpr iterator end() const
{
return {outerRange.end(*outer), outerRange.end(*outer)};
}
};
constexpr void test()
{
const std::array<std::array<int, 5>, 3> arr{};
nested_iterable range{arr};
}
<source>:13:20: error: multiple overloads of 'begin' instantiate to the same signature 'auto (const std::array<std::array<int, 5>, 3> &) const'
constexpr auto begin(T& t) const {
^
<source>:27:39: note: in instantiation of template class 'default_range<const std::array<std::array<int, 5>, 3> >' requested here
return *std::declval<OuterRange>().begin(outer);
...
<source>:110:21: note: while substituting deduced template arguments into function template '<deduction guide for nested_iterable>' [with Outer = const std::array<std::array<int, 5>, 3>, OuterRange = (no value), InnerRange = (no value)]
nested_iterable range{arr};
正如人们很容易知道的那样,default_range
不能为const std::array
实例化,因为当使用const
类型实例化时,begin
和end
方法变得不明确。
default_range
的想法是它的工作方式类似于默认std::less
但用户可以决定通过调用rbegin
来制作自己的。
这似乎是目前拼图中缺失的部分。我还尝试使用单个begin
而不是两种引用的重载,但这也不起作用。在这种情况下,T
始终需要是右值引用。
那么我该如何实现default_range
以便它适用于const
和非const
类型呢?
针对const T
情况的部分专用化default_range
,其中您不会重载有问题的函数:
template <typename T>
struct default_range<const T> {
constexpr auto begin(const T& t) const {
return t.begin();
}
constexpr auto end(const T& t) const {
return t.end();
}
};
另请注意,std::declval
只能在未计算的上下文中使用。话虽如此,inner_impl
需要重新实现,例如:
template <typename Outer, typename OuterRange>
using inner_impl_t = decltype(*std::declval<OuterRange>().begin(std::declval<Outer&>()));
相关文章:
- 1d 智能指针不适用于语法 (*)++
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 用于访问容器<T>数据成员的正确 API
- 重载操作程序时出错>>用于类中的字符串 memebr
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- C++中的cin.ignore()函数不适用于整个流
- 没有用于初始化C++中的变量模板的匹配构造函数
- 用于C++中带有数组和指针的循环
- 为什么它不适用于Visual 2019的原因
- 使用在用于SFINAE的void_t中具有参数的方法
- 在createdialog创建的窗口中捕获用于编辑控件的OnMouseMove消息
- 重载==不适用于二进制树
- Insert函数不适用于2 if语句C++
- 用于矢量处理的多个线程
- 使外部项目可用于find_package CMake
- 在子目录中使用target_sources()命令时用于单元测试(qtest)的项目结构
- 为什么模数运算符不适用于该代码
- 无法获得等效的 std::less 来用于嵌套迭代器
- 如何将重载的std::less用于std::map
- std::less<> 不适用于我的 std::map