Is there a difference between an std::pair
and an std::tuple
with only two members? (Besides the obvious that std::pair
requires two and only two members and tuple
may have more or less...)
There are some differences:
std::tuple
is not required by the standard to ever be standard-layout. Everystd::pair<T, Y>
is standard-layout if bothT
andY
are standard-layout.It's a bit easier to get the contents of a
pair
than atuple
. You have to use a function call in thetuple
case, while thepair
case is just a member field.
But that's about it.
tuple
standard layout? –
Acarology An std::tuple
's name is longer (one extra character). More of those characters are typed with the right hand, so easier for most people to type.
That said, std::pair
can only have two values - not zero, one, three or more. TWO values. A tuple, however, has almost no semantic limitation on the number of values. An std::pair
, therefore, is a more accurate, type safe type to use if you actually want to specify a pair of values.
std::tuple<>
is also type-safe (how could it not be?), and 2
is no semantically different than pair
. –
Cassondra This is a very late answer but note that, because std::pair
is defined with member variables, its size cannot be optimized using empty base class optimization (first
and second
must occupy distinct addresses, even if one or both is an empty class). This exacerbated by whatever alignment requirements second_type
has, so in the worst case the resulting std::pair
will be basically twice the size it needs to be.
std::tuple
only allows access through helper functions, so it's possible for it to derive from either type if one or the other is empty, saving on the overhead. GCC's implementation, at very least, definitely does this...you can poke through the headers to verify this but there's also this as evidence.
[[no_unique_address]]
should remove std::pair
's disadvantage. –
Kirkuk T
which is empty and trivially copyable. That last one means that it's OK to memcpy
from another existing T
. This will copy a single byte, since the size of an empty type is 1. And if you have a tuple<T, int>
, if you get a reference to the T
, you can copy a byte over it. If tuple
optimized T
's storage away, then it would undoubtedly overlap with int
. So copying that byte over partially copies over the int
, thus breaking it. –
Acarology memcpy
to an object: it's not OK if the object is a base class subobject (note: this is extended to no_unique_address member subobjects in C++20). There is no such carve out for members of a tuple
. –
Acarology tuple<T, T>
legally use a single byte for both members? We would then get &std::get<0>(tuple) == &std::get<1>(tuple)
, of course, and I'm not sure about the surprise effect of this – and thus if it still should better be avoided… –
Substituent get<0>
is required to return a pointer to a different object from get<1>
. Given that they are the same type, the only way that would be possible is if they have different address. –
Acarology Note that with C++ 17, one can use the same interface to read data from both pair and tuple with two elements.
auto [a, b] = FunctionToReturnPairOrTuple();
No need to use get<>
:)
It is, perhaps, worth noting that cppreference states:
"A pair is a specific case of a std::tuple with two elements."
std::pair
's change history this text did not appear when the question was asked. The earliest the text appears in the history is two years later –
Quadrisect For what it's worth, I find the GDB output of std::tuple to be far more difficult to read. Obviously if you need more than 2 values then std::pair won't work, but I do consider this a point in favor of structs.
std::get<0>(tupleName)
in a getter; GetX()
is a lot easier to read and shorter. It has a small disadvantage that if you forget to make it a const
method someone can do something stupid like this: GetX() = 20;
. –
Quadrisect © 2022 - 2024 — McMap. All rights reserved.
.first
and.second
are handy, they offer no help if a third (or more) member(s) are required in a code change. I've noticed I tend to usestd::get
regardless in any Getters that way I don't need to change everything, just the datatypes and anymake_pair
calls tomake_tuple
calls. – Quadrisect