I\'m writing a custom iterator that, when dereferenced returns a tuple of references. Since the tuple itself is ephemeral, I don\'t think I can return a reference from oper
The answer I came up with was to write a tuple wrapper class:
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);
}
And a get function that can be found with ADL, since the conversion operator doesn't get called when doing 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);
}
It's not ideal, but I think it will work well enough.
You can place the std::tuple
as a data member and return a reference to that:
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;
};
On rare occasions it may be desirable to get an lvalue reference to temporary. This easily achieved with a cast opposite to std::move
:
template <typename T>
T & stay(T && t) { return t; }
Usage:
std::swap(stay(foo()), stay(bar()));
As you already said, if you can't change the call site, your best option may be to write your own reference wrapper and use ADL for that:
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]); } }