Consider the following code:
#include
#include
struct A
{
A() {}
A(const A&) { std::cout << "Copy" << std::endl; }
A(A&&) { std::cout << "Move" << std::endl; }
};
template
struct B
{
T x;
};
#define MAKE_B(x) B{ x }
template
B make_b(T&& x)
{
return B { std::forward(x) };
}
int main()
{
std::cout << "Macro make b" << std::endl;
auto b1 = MAKE_B( A() );
std::cout << "Non-macro make b" << std::endl;
auto b2 = make_b( A() );
}
This outputs the following:
Macro make b
Non-macro make b
Перемещение
Обратите внимание, что b1 строится без перемещения, но построение b2 требует перемещения.
Мне также нужно ввести вывод, поскольку A
в реальной жизни может быть сложным типом, который сложно написать явно. Мне также нужно иметь возможность вкладывать вызовы (например, make_c (make_b (A ()))
).
Возможна ли такая функция?
Дополнительные мысли:
N3290 Final C + + 0x черновик страницы 284:
Это исключение операций копирования / перемещения, называется копированием, разрешено в следующие обстоятельства:
когда временный объект класса , имеющий не привязан к ссылке (12.2) будет скопирован / перемещен в класс объект с таким же CV-неквалифицированным типа, операция копирования / перемещения может быть опущено путем создания временного объект прямо в цель omitted copy/move
Unfortunately this seems that we can't elide copies (and moves) of function parameters to function results (including constructors) as those temporaries are either bound to a reference (when passed by reference) or no longer temporaries (when passed by value). It seems the only way to elide all copies when creating a composite object is to create it as an aggregate. However, aggregates have certain restrictions, such as requiring all members be public, and no user defined constructors.
I don't think it makes sense for C++ to allow optimizations for POD C-structs aggregate construction but not allow the same optimizations for non-POD C++ class construction.
Is there any way to allow copy/move elision for non-aggregate construction?
My answer:
This construct allows for copies to be elided for non-POD types. I got this idea from David Rodríguez's answer below. It requires C++11 lambdas. In this example below I've changed make_b
to take two arguments to make things less trivial. There are no calls to any move or copy constructors.
#include
#include
struct A
{
A() {}
A(const A&) { std::cout << "Copy" << std::endl; }
A(A&&) { std::cout << "Move" << std::endl; }
};
template
class B
{
public:
template
B(const LAMBDA1& f1, const LAMBDA2& f2) : x1(f1()), x2(f2())
{
std::cout
<< "I'm a non-trivial, therefore not a POD.\n"
<< "I also have private data members, so definitely not a POD!\n";
}
private:
T x1;
T x2;
};
#define DELAY(x) [&]{ return x; }
#define MAKE_B(x1, x2) make_b(DELAY(x1), DELAY(x2))
template
auto make_b(const LAMBDA1& f1, const LAMBDA2& f2) -> B
{
return B( f1, f2 );
}
int main()
{
auto b1 = MAKE_B( A(), A() );
}
If anyone knows how to achieve this more neatly I'd be quite interested to see it.
Previous discussion:
This somewhat follows on from the answers to the following questions:
Can creation of composite objects from temporaries be optimised away?
Avoiding need for #define with expression templates
Eliminating unnecessary copies when building composite objects