gpt4 book ai didi

Custom view works for vector, but not array or initializer_list(自定义视图适用于向量,但不适用于数组或初始化器_列表)

转载 作者:bug小助手 更新时间:2023-10-28 10:33:50 26 4
gpt4 key购买 nike



All code details for this question are in this godbolt example:

这个问题的所有代码细节都在这个Godbolt示例中:


#include <array>
#include <iostream>
#include <random>
#include <range/v3/all.hpp>
#include <string>
#include <type_traits>
#include <unordered_set>
#include <vector>

#include "fmt/format.h"
#include "fmt/ranges.h"

template <typename T>
decltype(auto) deref(T&& t) {
return std::forward<T>(t).get();
}

template <ranges::range Range>
class deref_view : public ranges::view_base {
public:
struct iterator;
deref_view() = default;
deref_view(ranges::range auto&& base) : m_base(base) {}

iterator begin() { return ranges::begin(m_base); }
iterator end() { return ranges::end(m_base); }

private:
Range m_base;
};

template <ranges::range Range>
struct deref_view<Range>::iterator : public ranges::iterator_t<Range> {
using base = ranges::iterator_t<Range>;
using value_type =
std::remove_cvref_t<decltype(deref(*(std::declval<Range>().begin())))>;
using difference_type = ranges::range_difference_t<Range>;

iterator() = default;

iterator(const base& b) : base{b} {}

iterator operator++(int) { return static_cast<base&>(*this)++; }

iterator& operator++() {
++static_cast<base&>(*this);
return (*this);
}

decltype(auto) operator*() const {
return deref(*static_cast<base>(*this));
}
};

template <ranges::range Range>
deref_view(Range&&) -> deref_view<ranges::cpp20::views::all_t<Range> >;

struct deref_fn {
template <typename Rng>
auto operator()(Rng&& rng) const {
return deref_view{ranges::views::all(std::forward<Rng>(rng))};
}

template <typename Rng>
friend auto operator|(Rng&& rng, deref_fn const&) {
return deref_view{ranges::views::all(std::forward<Rng>(rng))};
}
};

// add the deref view to the ranges namespace

namespace ranges::views {

constexpr deref_fn deref{};

} // namespace ranges::views

int main() {
std::vector v{1, 2, 3, 4, 5, 6};

// auto list = {std::ref(v), std::ref(v)}; // this does NOT work
auto list = std::array{std::ref(v), std::ref(v)}; // this does NOT work
// auto list = std::vector{std::ref(v), std::ref(v)}; // this WORKS

for (const auto& arr : list | ranges::views::deref) {
fmt::print("{}\n", arr);
}

return 0;
}

Building on my previous question Create a custom transformable view in ranges-v3, I have a deref view which merely dereferences std::reference_wrappers by calling .get() on the range's elements,

在我上一个问题的基础上,在Range-v3中创建一个定制的可转换视图,我有一个deref视图,它只是通过在范围的元素上调用.get()来取消引用std::Reference_wrappers,


template < typename T >
decltype(auto) deref(T&& t)
{
return std::forward< T >(t).get();
}

I have used this method to create a deref view for the ranges-v3 library which has worked for my use cases as expected. However, I cannot apply it to a std::array or std::initializer_list container, but it does work for a std::vector. The error I get for e.g. std::array is:

我已经使用此方法为Range-v3库创建了deref视图,该库已按预期用于我的用例。但是,我不能将其应用于std::数组或std::Initializer_list容器,但它确实适用于std::VECTOR。例如,对于std::数组,我得到的错误是:


<source>: In instantiation of 'struct deref_view<ranges::ref_view<std::array<std::reference_wrapper<std::vector<int> >, 2> > >::iterator':
<source>:120:49: required from here
<source>:66:29: error: base type 'ranges::iterator_t<ranges::ref_view<std::array<std::reference_wrapper<std::vector<int> >, 2> > >' {aka 'std::reference_wrapper<std::vector<int> >*'} fails to be a struct or class type
66 | struct deref_view< Range >::iterator: public ranges::iterator_t< Range > {
| ^~~~~~~~
<source>: In function 'int main()':
<source>:120:49: error: no match for 'operator!=' (operand types are 'deref_view<ranges::ref_view<std::array<std::reference_wrapper<std::vector<int> >, 2> > >::iterator' and 'deref_view<ranges::ref_view<std::array<std::reference_wrapper<std::vector<int> >, 2> > >::iterator')
120 | for(const auto& arr : list | ranges::views::deref) {
| ^~~~~
<source>: In instantiation of 'decltype(auto) deref_view<Range>::iterator::operator*() const [with Range = ranges::ref_view<std::array<std::reference_wrapper<std::vector<int> >, 2> >]':
<source>:120:49: required from here
<source>:83:53: error: invalid 'static_cast' from type 'const deref_view<ranges::ref_view<std::array<std::reference_wrapper<std::vector<int> >, 2> > >::iterator' to type 'deref_view<ranges::ref_view<std::array<std::reference_wrapper<std::vector<int> >, 2> > >::iterator::base' {aka 'std::reference_wrapper<std::vector<int> >*'}
83 | decltype(auto) operator*() const { return deref(*static_cast< base >(*this)); }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~

What specifics am I missing in how ranges handle arrays and vectors?

在范围处理数组和向量的方式中,我遗漏了哪些细节?


(The problem also occurs with std::ranges)

(std::Range也会出现此问题)


更多回答
优秀答案推荐

The compiler error here indicates the issue:

此处的编译器错误指示问题:


<source>:66:29: error: base type 'ranges::iterator_t<ranges::ref_view<std::array<std::reference_wrapper<std::vector<int> >, 2> > >' {aka 'std::reference_wrapper<std::vector<int> >*'} fails to be a struct or class type

When you write:

当你写下这封信时:


template <ranges::range Range>
struct deref_view<Range>::iterator : public ranges::iterator_t<Range> {

You're only allowed to inherit from class types. But iterator_t<Range> need not actually be a class type. And in the particular case that you're trying here, it's not a class type - it's just a pointer (specifically std::reference_wrapper<std::vector<int> >*). That's because std::array<T, N>'s iterator is allowed to be just T* or T const* (it's implementation defined, but a simple pointer meets all the requirements).

您只允许从类类型继承。但是Iterator_t 实际上不需要是类类型。在这里尝试的特定情况下,它不是一个类类型--它只是一个指针(具体地说,就是std::Reference_wrapper *)。这是因为std::数组 ‘S迭代器只允许为T*或T const*(它是实现定义的,但一个简单的指针满足所有要求)。


The solution here is straightforward: instead of inheriting from ranges::iterator_t<Base>, have a member of that type. This is what all the range adapters have to do - first because of the pointer issue, since pointers are valid iterators, but also because avoiding inheritance ensures that you can actually get all the operations correct.

这里的解决方案很简单:不是从Range::Iterator_t继承,而是拥有该类型的成员。这是所有范围适配器都必须做的--首先是因为指针问题,因为指针是有效的迭代器,而且还因为避免继承确保您可以实际正确地执行所有操作。


This additionally actually makes the implementation cleaner anyway, since you can just refer to the base member instead of having to write static_cast<base>(*this) everywhere.

此外,这实际上使实现更加简洁,因为您可以只引用基成员,而不必在任何地方编写Static_Cast(*this)。


Demo.

演示。


更多回答

thanks so much for your effort! I wasn't aware of this iterator oddity. It works well now with your adaptation :)

非常感谢您的努力!我没有意识到这种迭代器的奇怪之处。它现在可以很好地适应您的需求:)

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com