Consider the following example:
void consume(foo&&); template <typename Tuple> void consume_tuple_first(Tuple&& t) { consume(std::get<0>(std::forward<Tuple>(t))); } int main() { consume_tuple_first(std::tuple{foo{}}); }
In this case, we know that std::tuple{foo{}} is temporary and that it will live for the duration of the consume_tuple_first(std::tuple{foo{}}) expression consume_tuple_first(std::tuple{foo{}}) .
We want to avoid unnecessary copy and move, but still extend the foo{} consume to consume .
The only way to do this is: std::get to return the rvalue link when called with a temporary instance of std::tuple .
live example in wandbox
Changing std::get<0>(std::forward<Tuple>(t)) to std::get<0>(t) creates a compilation error (as expected) ( in wandbox ).
Having an alternative get that returns a value leads to additional unnecessary movement:
template <typename Tuple> auto myget(Tuple&& t) { return std::get<0>(std::forward<Tuple>(t)); } template <typename Tuple> void consume_tuple_first(Tuple&& t) { consume(myget(std::forward<Tuple>(t))); }
live example in wandbox
but can anyone explain to me why this was considered the best option?
Because it includes additional generic code that smoothly distributes rvalue temporary references when accessing tuples. The alternative of returning by value may lead to unnecessary movement actions.
source share