gpt4 book ai didi

c++ - 与 get、tie 和其他元组操作一起使用的元组包装器

转载 作者:行者123 更新时间:2023-12-03 20:50:32 33 4
gpt4 key购买 nike

我写了一个花哨的“zip 迭代器”,它已经完成了许多角色(可以用于 for_each、复制循环、容器迭代器范围构造函数等......)。
在处理所涉及的对/元组的所有模板代码下,归结为迭代器的解引用运算符返回一个元组/一对引用,而不是对元组/对的引用。
我希望我的迭代器与 std::sort 一起工作,所以我需要能够做 swap(*iter1, *iter2)并在迭代的原始容器中切换基础值。
代码和一个小demo可以看这里(有点看不懂):http://coliru.stacked-crooked.com/a/4fe23b4458d2e692
尽管 libstdc++ 的排序使用 std::iter_swap其中调用 swap ,例如libc++ 没有,它只是调用 swap直接,所以我想要一个涉及 swap 的解决方案作为定制点。
我已经尝试过(并且非常接近工作)而不是返回 std::pair/std::tuple来自 operator*正如我现在所做的,返回的是一个简单的包装器类型。目的是让包装器表现得好像它是 std::pair/std::tuple ,并允许我写一个 swap为它发挥作用。
它看起来像这样:

template<typename... ValueTypes>
struct TupleWrapper : public PairOrTuple_t<ValueTypes...>
{
using PairOrTuple_t<ValueTypes...>::operator=;
template<typename... TupleValueTypes>
operator PairOrTuple_t<TupleValueTypes...>() const
{
return static_cast<PairOrTuple_t<ValueTypes...>>(*this);
}
};

template<std::size_t Index, typename... ValueTypes>
decltype(auto) get(TupleWrapper<ValueTypes...>& tupleWrapper)
{
return std::get<Index>(tupleWrapper);
}
template<std::size_t Index, typename... ValueTypes>
decltype(auto) get(TupleWrapper<ValueTypes...>&& tupleWrapper)
{
return std::get<Index>(std::forward<TupleWrapper<ValueTypes...>>(tupleWrapper));
}
template<typename... ValueTypes,
std::size_t... Indices>
void swap(TupleWrapper<ValueTypes...> left,
TupleWrapper<ValueTypes...> right,
const std::index_sequence<Indices...>&)
{
(std::swap(std::get<Indices>(left), std::get<Indices>(right)), ...);
}

template<typename... ValueTypes>
void swap(TupleWrapper<ValueTypes...> left,
TupleWrapper<ValueTypes...> right)
{
swap(left, right, std::make_index_sequence<sizeof...(ValueTypes)>());
}


namespace std
{
template<typename... ValueTypes>
class tuple_size<utility::implementation::TupleWrapper<ValueTypes...>> : public tuple_size<utility::implementation::PairOrTuple_t<ValueTypes...>> {};
template<std::size_t Index, typename... ValueTypes>
class tuple_element<Index, utility::implementation::TupleWrapper<ValueTypes...>> : public tuple_element<Index, utility::implementation::PairOrTuple_t<ValueTypes...>> {};
}
完整代码在这里: http://coliru.stacked-crooked.com/a/951cd639d95af130 .
operator* 中返回此包装器似乎可以编译(至少在 GCC 上)但会产生垃圾。
在 Clang 的 libc++ 上, std::tie无法编译。
两个问题:
  • 我怎样才能用 libc++ 编译它(魔术似乎在于 TupleWrapper 的转换运算符?)
  • 为什么结果是错误的,我做错了什么?

  • 我知道它有很多代码,但是我不能把它写得更短,因为所有交换元组包装器的小例子对我来说都很好。

    最佳答案

    第一个问题
    问题之一是ZipIterator类不满足 RandomAccessIterator 的要求.

  • std::sort需要 RandomAccessIterator s 作为其参数
  • RandomAccessIterator s 必须是 BidirectionalIterator s
  • BidirectionalIterator s 必须是 ForwardIterator s

  • ForwardIterator s 的条件是 ::reference 必须是 value_type&/ const value_type& :

    The type std::iterator_traits<It>::reference must be exactly

    • T& if It satisfies OutputIterator (It is mutable)
    • const T& otherwise (It is constant)

    (where T is the type denoted by std::iterator_traits<It>::value_type)


    其中 ZipIterator目前没有实现。
    它适用于 std::for_each和类似的函数,只需要迭代器满足 InputIterator 的要求/ OutputIterator .

    The reference type for an input iterator that is not also a LegacyForwardIterator does not have to be a reference type: dereferencing an input iterator may return a proxy object or value_type itself by value (as in the case of std::istreambuf_iterator).


    tl;博士: ZipIterator可以用作 InputIterator/ OutputIterator ,但不是 ForwardIterator , 其中 std::sort需要。
    第二个问题
    @T.C.their comment 中指出 std::sort允许将值移出容器,然后再将它们移回。

    The type of dereferenced RandomIt must meet the requirements of MoveAssignable and MoveConstructible.


    其中 ZipIterator当前无法处理(它从不复制/移动引用的对象),所以这样的事情不能按预期工作:
    std::vector<std::string> vector_of_strings{"one", "two", "three", "four"};
    std::vector<int> vector_of_ints{1, 2, 3, 4};


    auto first = zipBegin(vector_of_strings, vector_of_ints);
    auto second = first + 1;

    // swap two values via a temporary
    auto temp = std::move(*first);
    *first = std::move(*second);
    *second = std::move(temp);

    // Result:
    /*
    two, 2
    two, 2
    three, 3
    four, 4
    */
    ( test on Godbolt )
    结果
    不幸的是,不可能创建一个迭代器来动态生成元素并且可以用作 ForwardIterator使用当前标准(例如 this question )
  • 你当然可以编写自己的算法,只需要 InputIterator s/OutputIterator s(或以不同方式处理您的 ZipIterator)
    例如一个简单的冒泡排序:( Godbolt )
  • template<class It>
    void bubble_sort(It begin, It end) {
    using std::swap;

    int n = std::distance(begin, end);

    for (int i = 0; i < n-1; i++) {
    for (int j = 0; j < n-i-1; j++) {
    if (*(begin+j) > *(begin+j+1))
    swap(*(begin+j), *(begin+j+1));
    }
    }
    }
  • 或者换个ZipIterator类满足RandomAccessIterator .
    不幸的是,如果不将元组放入像数组这样的动态分配结构中(您可能试图避免这种结构),我想不出一种可能的方法
  • 关于c++ - 与 get、tie 和其他元组操作一起使用的元组包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63137322/

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