交换参考的临时元素

swap temporary tuples of references

本文关键字:元素 参考 交换      更新时间:2023-10-16

我正在编写一个自定义迭代器,当reterended返回引用元组时。由于元组本身是短暂的,因此我认为我无法返回操作员*()的参考。我认为我的迭代器在语义上是有意义的,因为它具有参考语义,即使操作员*返回一个值。

问题是,当我尝试调用std :: swap时(或者,当std :: sort所做时),如下所示,我会遇到错误,因为互换期望l值。这个问题有简单的解决方案吗?

#include <vector>
class test {
  public:
  test()
    :v1(10), v2(10)
  {}
  class iterator {
    public:
    iterator(std::vector<int>& _v1,
             std::vector<int>& _v2)
      :v1(_v1), v2(_v2){}
    std::tuple<int&, int&> operator*(){
      return std::tuple<int&, int&>{v1[5], v2[5]};
    }
    std::vector<int>& v1;
    std::vector<int>& v2;
  };
  std::vector<int> v1, v2;
};

int main(){
  test t;
  //error, Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/type_traits:3003:1: note: candidate function [with _Tp = std::__1::tuple<int &, int &>] not viable: expects an l-value for 1st argument
  //deep within the bowels of std::sort ...
  std::swap(*(test::iterator(t.v1, t.v2)),
            *(test::iterator(t.v1, t.v2)));
}

在极少数情况下,可能需要获得临时引用。与std::move相对的演员很容易实现:

template <typename T>
T & stay(T && t) { return t; }

用法:

std::swap(stay(foo()), stay(bar()));

正如您已经说过的,如果您无法更改呼叫网站,最好的选择可能是编写自己的参考包装器并使用ADL:

namespace detail
{
    struct IntRefPair
    {
        int & a, & b;
        IntRefPair(int & x, int & y) : a(x), b(y) {}
    };
    void swap(IntRefPair && lhs, IntRefPair && rhs)
    { 
        std::swap(lhs.a, rhs.a);
        std::swap(lhs.b, rhs.b);
    }
}
// ...
IntRefPair operator*() { return IntRefPair(v1[5], v2[5]); } }

我想出的答案是写一个元组包装类:

template<typename ... Types>
struct tupleWrapper{
   std::tuple<Types...> data;
   tupleWrapper(std::tuple<Types...> _data) : data{_data}
   {}
   operator std::tuple<Types...> () {return data;}
   std::tuple<Types...>& asTuple() {return data;}
 };
template<typename ... Types>
void swap(tupleWrapper<Types ...> t1, tupleWrapper<Types ...> t2){
  std::swap(t1.data, t2.data);
}

和一个可以使用ADL找到的GET功能,因为转换操作员在tad for std :: get。

时不会被调用
template<int N, typename ...Ts>
  auto get(tupleWrapper<Ts...> tw)->decltype(std::get<N>(tw.data)){
    return std::get<N>(tw.data);
}

这不是理想的,但我认为它可以很好地工作。

您可以将std::tuple作为数据成员放置并返回对此的引用:

class iterator
{
public:
    iterator(std::vector<int>& _v1,
             std::vector<int>& _v2)
      : tup(_v1[5], _v2[5]) {}
    tuple_of_references& operator*() const
    {
        return tup;
    }
private:
    typedef std::tuple<int&, int&> tuple_of_references; // just to cut down size
    tuple_of_references tup;
};