Std::Pair of References

std::pair of references

No, you cannot do this reliably in C++03, because the constructor of pair takes references to T, and creating a reference to a reference is not legal in C++03.

Notice that I said "reliably". Some common compilers still in use (for GCC, I tested GCC4.1, @Charles reported GCC4.4.4) do not allow forming a reference to a reference, but more recently do allow it as they implement reference collapsing (T& is T if T is a reference type). If your code uses such things, you cannot rely on it to work on other compilers until you try it and see.

It sounds like you want to use boost::tuple<>

int a, b;

// on the fly
boost::tie(a, b) = std::make_pair(1, 2);

// as variable
boost::tuple<int&, int&> t = boost::tie(a, b);
t.get<0>() = 1;
t.get<1>() = 2;

Are the values stored in std::pair by reference or by value?

A std::pair, in your specific case, is nothing more than, in so many words:

struct pair {
int first;
int second;
};

first and second, in your std::pair, are non-reference class members. The full definition of std::pair is pretty much

template<typename T1, typename T2> struct pair {
T1 first;
T2 second;
};

How can I have a pair with reference inside vector?

Since C++14 std::make_pair is defined as

template< class T1, class T2 >
std::pair<V1,V2> make_pair( T1&& t, T2&& u );

where V1 and V2 are std::decay<T1>::type and std::decay<T2>::type respectively.

This means that your make_pair<const int&, int> calls do not really produce pairs with references as their first elements (contrary to what you apparently believed). They actually produce temporaries of pair<int, int> type. At this point you lose any attachment to the original int object stored in your unique_ptr.

When you pass these pair<int, int> temporaries to push_back, they get implicitly converted to temporaries of pair<const int&, int> type, which is your vector's element type. Through this mechanism you attach references inside your vector's element to int members of those pair<int, int> temporaries produced by make_pair (not to int objects stored in your unique_ptrs). Once the temporaries expire, the references go sour.


In this case you can eliminate this specific problem by avoiding make_pair altogether and simply directly constructing std::pair objects of proper type, e.g.

vector.push_back(std::pair<const int&, int>(*ptr, 11));

but you might run into other problems caused by raw references later.

How does this const reference for std::pair work?

When you do

const std::pair<key_type, T>& reference = *map_iterator;

*map_iterator returns a std::pair<const key_type, T>&. You then copy initialize a std::pair<key_type, T> from that, and then you bind reference to that temporary variable. Because you have a reference to const, this will extend the lifetime of that temporary to be the lifetime of the reference and you now have an element that is a copy of the one from the map. Basically you've done

std::pair<key_type, T> copy = *map_iterator; 

The above conversion sequence works because you are allowed up to one user defined conversion in initialization and the compiler will try to do that to give you a valid initialization.

read values of reference direct by std::pair std::array std::array u_int16_t,2 ,1 ,std::string

std::get returns references. You can just store these references:

const auto& PosTextfield = std::get<0>(out);
const auto& val = std::get<1>(out);

or

const auto& PosTextfield = out.first;
const auto& val = out.second;

or you can replace the auto keywords with the actual types if you prefer. const can be removed as well, since auto will deduce it, but writing it explicitly makes it clear to the reader that the two references are non-modifiable.

This doesn't create any new objects. The references refer to the elements of the pair passed to the function.

Or just refer to the element directly where you want to use them with out.first and out.second or std::get<0>(out) and std::get<1>(out).

std::pair with reference to unique pointer

std::make_pair() will automatically decay any references given to it to their value types.

The deduced types V1 and V2 are std::decay<T1>::type and std::decay<T2>::type (the usual type transformations applied to arguments of functions passed by value) unless application of std::decay results in std::reference_wrapper<X> for some type X, in which case the deduced type is X&.

https://en.cppreference.com/w/cpp/utility/pair/make_pair

Remove your explicit instantiation of the type parameters of std::make_pair() and wrap the emplace_back() call with std::ref:

return std::make_pair(
std::move(panelID),
std::ref(panels.emplace_back())
);

Alternatively, you can explicitly make the std::pair:

return std::pair<PanelID, Panel_Ptr&>(
std::move(panelID),
panels.emplace_back()
);

Finally, to note on your code, you are calling std::move() on your PanelID type even though it is just an integer. std::move() is useless in that scenario, so removing it entirely would make your code clearer.

Though, putting the generation of panelID on a separate statement is still necessary due to the unspecified order of evaluation of arguments passed to functions. Good awareness of this fact.

Why does std::make_pair return a pair of reference types

As far as I know make_pair has the following prototype:

template<class Type1, class Type2>
std::pair<Type1,Type2> make_pair(Type1 first_value, Type2 second_value);

(Note: slightly different since C++11)

See also http://en.cppreference.com/w/cpp/utility/pair/make_pair.

This is also what the standard says in §20.3.3 [pairs.spec]. So this must be an error in the book (or you may have overlooked something).



Related Topics



Leave a reply



Submit