-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
F.21 Don't return tuples #2166
F.21 Don't return tuples #2166
Conversation
2e154a9
to
21cf8b5
Compare
Editors call: Thanks! We're favorable to removing the suggestion to use |
c42b2ae
to
bc0c546
Compare
@hsutter I have mostly kept the old note, but with some modernizing changes now. The old note also mentioned a " Is this a good compromise? The current build fails because of a spell check in some part I haven't touched. |
Interim ack: Thanks! This looks much better. I fixed the spell check issue. |
As I noted in P2497R0, it's not an expected-like type, because both members have meaning in the error case. It's not a sum type, it's a product type. The reason it's a named struct not a pair is for the reasons you've given elsewhere in the PR why |
Co-authored-by: Jonathan Wakely <[email protected]>
Co-authored-by: Jonathan Wakely <[email protected]>
Co-authored-by: Jonathan Wakely <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates, LGTM
Thanks! |
This PR overhauls and modernizes the current advice. In short, we should not recommend returning
pair
ortuple
.Rationale
1. Modern C++ has excellent support for
struct
C++20 has added
operator<=> = default
eliminates practically all uses ofstd::pair
. Furthermore, it has made direct-initialization of aggregate types possible, so thatstruct
s can be used withemplace
, taking away even more reasons to usestd::pair
.struct
also supports aggregate initialization with designated initializers, unlikestd::pair
andstd::tuple
, which aren't aggregates.2.
std::pair
andstd::tuple
are bad for code qualitystd::pair
hurts code quality. Replacing meaningful member names withfirst
andsecond
is strictly worse. The few cases where there is no meaningful name are usually homogeneous cases (e.g.std::minmax
could returnstd::array<T, 2>
).Consensus in the C++ community has overwhelmingly shifted against the use of
std::pair
orstd::tuple
:std::minmax
returnedstd::pair
butstd::ranges::minmax
returnstd::ranges::min_max_result
.std::from_chars
returnsstd::from_chars_result
.std::tuple
is even worse because it forces the user to access members withstd::get<N>
which is even more confusing than.first
and.second
, and tremendously more confusing than.meaningful_name
.std::tuple
is only useful in variadic templates. This exception is left in the guideline.3.
std::pair
andstd::tuple
have legacy baggagestd::pair
is an incredibly bloated type for what it does. It has 11 constructors while providing relatively little value in most of its uses.std::tuple
has 28 constructors.Furthermore,
std:tuple
is not ABI-trivial in libstdc++, which results instd::tuple<int>
being passed via stack and not via register. Overall, a simplestruct
can be a major boost to compilation speed and even runtime performance.4. Almost no return type obviously meets the requirement in the old guideline
The old wording states:
Almost no function obviously meets this hurdle.
std::minmax
doesn't because it returns a one-dimensional range, specified by a minimum and maximum, not two entirely independent entities.std::from_chars
doesn't because it returns a pre-C++23std::expected
-like type. In general, pairs where one member indicates success are abstracted by an optional/expected value.I find this guideline wishy washy because you can almost always argue that the two entities are not independent, or the other way.
The only example in the standard library I can think of where
std::pair
clearly makes sense is key/value pairs in `std::map, since the key and value can be accessed and used independently, other than being located in the same data structure. Even so, I'm sure you'll find someone who would argue they are not two independent entities.5.
std::tie
is often bad practiceThe current guideline contains the positive example:
This is bad because
std::tie
-assignment prevents this)Someothertype
is meant to bebool
-like)std::tie
still has a small handful of uses, but most have been replaced bystd::tie
is more of a historical relic and increasingly niche utility, rather than something we need to recommend in this guideline, especially if what we're recommend is bad practice that conflicts with other rules.