I would expect that in C++20 the following code prints nothing between prints of A and B (since I expect guaranteed RVO to kick in). But output is:
A
Bye
B
C
Bye
Bye
So presumably one temporary is being created.
#include <iostream>
#include <tuple>
struct INeedElision{
int i;
~INeedElision(){
std::cout << "Bye\n";
}
};
std::tuple<int, INeedElision> f(){
int i = 47;
return {i, {47}};
}
INeedElision g(){
return {};
}
int main()
{
std::cout << "A\n";
auto x = f();
std::cout << "B\n";
auto y = g();
std::cout << "C\n";
}
What is the reason for this behavior? Is there a workaround to avoid copy (without using pointers)?
When constructing
std::tuple<int, INeedElision>from{i, {47}}, the selected constructor ofstd::tupletakes elements by lvalue-reference toconst.Then when use
{i, {47}}as the initializer, a temporaryINeedElisionwill be constructed and then passed to the constructor ofstd::tuple(and get copied). The temporary object will be destroyed immediately and you'll see "Bye" between "A" and "B".BTW: The 3rd constructor of
std::tuplewon't be used for this case.It's a constructor template, and braced-init-list like
{47}doesn't have type and can't be deduced by template argument deduction.On the other hand, if
INeedElisionhas a converting constructor takingint, and make the initializer as{i, 47}, the 3rd constructor ofstd::tuplewill be used and no temporaryINeedElisionis constructed; the element will be constructed in-place from theint47.LIVE