Рассмотрим следующий код:
#include <iostream>
#include <type_traits>
struct A
{
A() {}
A(const A&) { std::cout << "Copy" << std::endl; }
A(A&&) { std::cout << "Move" << std::endl; }
};
template <class T>
struct B
{
T x;
};
#define MAKE_B(x) B<decltype(x)>{ x }
template <class T>
B<T> make_b(T&& x)
{
return B<T> { std::forward<T>(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() );
}
Выводит следующее:
Macro make b
Не макрос сделать b
Переместить
Обратите внимание, что b1 строится без перемещения, но для построения b2 требуется переход.
Мне также нужно вводить дедукцию, так как A
в реальной жизни может быть сложным типом, который трудно писать явно. Мне также нужно иметь возможность вставлять вызовы (т.е. make_c(make_b(A()))
).
Возможна ли такая функция?
Дальнейшие мысли:
N3290 Final С++ 0x черновик стр. 284:
Это исключение операций копирования/перемещения, называемый копией, разрешен в следующие обстоятельства:
когда объект временного класса , который имеет не были связаны с ссылкой (12.2) будет скопирован/перенесен в класс объект с тем же cv-unqualified тип, операция копирования/перемещения может быть опущено путем создания временного объекта непосредственно в цель omitted copy/move
К сожалению, нам кажется, что мы не можем копировать (и перемещать) функциональные параметры для результатов функции (включая конструкторы), поскольку эти временные числа либо привязаны к ссылке (при передаче по ссылке), либо уже не временные (когда они передаются по стоимость). Кажется, единственный способ избежать всех копий при создании составного объекта - создать его как совокупность. Однако агрегаты имеют определенные ограничения, такие как требование, чтобы все члены были общедоступными и не определялись определенными конструкторами.
Я не думаю, что С++ позволяет оптимизировать структуру агрегатов POD C-structs, но не допускать одинаковых оптимизаций для построения класса не-POD С++.
Есть ли способ разрешить копирование/перемещение elision для неагрегатной конструкции?
Мой ответ:
Эта конструкция позволяет копировать копии для не-POD-типов. Я получил эту идею от ответа Дэвида Родригеса ниже. Это требует С++ 11 lambdas. В этом примере ниже я изменил make_b
, чтобы принять два аргумента, чтобы сделать вещи менее тривиальными. Нет вызовов для каких-либо конструкторов перемещения или копирования.
#include <iostream>
#include <type_traits>
struct A
{
A() {}
A(const A&) { std::cout << "Copy" << std::endl; }
A(A&&) { std::cout << "Move" << std::endl; }
};
template <class T>
class B
{
public:
template <class LAMBDA1, class LAMBDA2>
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 <class LAMBDA1, class LAMBDA2>
auto make_b(const LAMBDA1& f1, const LAMBDA2& f2) -> B<decltype(f1())>
{
return B<decltype(f1())>( f1, f2 );
}
int main()
{
auto b1 = MAKE_B( A(), A() );
}
Если кто-то знает, как добиться этого более аккуратно, мне было бы очень интересно увидеть его.
Предыдущее обсуждение:
Это несколько вытекает из ответов на следующие вопросы:
Можно ли оптимизировать создание составных объектов из временных рядов?
Избежать необходимости #define с шаблонами выражений
Устранение ненужных копий при создании составных объектов