Строительный помощник make_XYZ, позволяющий RVO и вывод типа, даже если XZY имеет ограничение неточности
UPDATE1: С++ 17 добавлен вывод типа для конструкторов, что не означает, что свободная функция является более низким решением.
UPDATE2: С++ 17 добавлен гарантированный экземпляр копии (копия даже не выполняется концептуально). Так что с С++ 17 мой код действительно работает и с оптимальной производительностью. Но код Martinho, использующий инициализацию скобки для возвращаемого значения, по-прежнему является более чистым решением, которое я считаю. Но проверьте этот ответ от Барри и комментарий от T.C.
OLD POST: Вывод типа не работает для конструкторов (по крайней мере до и включая С++ 11). Общим решением является полагаться на RVO (Оптимизация возвращаемого значения) и писать функцию шаблона make_XYZ, которая пересылает свои параметры в конструктор. Пример: std::make_tuple
.
Любой шаблон acrobat, который знает обходное решение, чтобы сделать эту работу, когда политика nocopy мешает? Допустимое решение должно по-прежнему допускать RVO.
Кроме того, исчезнет ли необходимость в make_XYZ с С++ 14?
#include <iostream>
template <typename T>
struct XYZ
{
// remove following two lines to make the code compile
XYZ (XYZ const & rhs) = delete;
XYZ (XYZ && rhs) = delete;
T i;
XYZ (T i):i(i)
{
}
};
template <typename T>
XYZ<T> make_XYZ (T && i)
{
return XYZ<T>(std::forward<T>(i));
}
int main ()
{
auto x = make_XYZ(1);
std::cout << x.i << std::endl;
}
Ответы
Ответ 1
Если существует неявный конструктор, то действительно возможно вернуть не-копируемый и недвижущийся тип по значению. См. Живой пример: http://coliru.stacked-crooked.com/a/89ef9d3115924558.
template <typename T>
XYZ<T> make_XYZ (T && i)
{
return { std::forward<T>(i) };
}
Трудный бит здесь заключается в том, что { ... }
не создает временное и перемещает его в возвращаемое значение. Он непосредственно инициализирует возвращаемое значение. Нет копии и не перемещается, и это не имеет значения, применяется ли какая-либо оптимизация (она не будет компилироваться, если она требует оптимизации для работы).
Однако, поскольку тип не копируется и не перемещается, вы не сможете сохранить его в локальной переменной по значению. Тем не менее, вы можете использовать старый временный трюк для продления жизни:
auto&& x = make_XYZ(1);
Ответ 2
RVO - это только оптимизация; копия/перемещение должны быть доступны для использования при возврате объекта (временного или имени) из функции.
Я предлагаю использовать make_XYZ
только в неценовом контексте, используя decltype
:
#include <utility>
struct noncopy {
noncopy() {}
noncopy(noncopy &&) = delete;
noncopy(const noncopy &) = delete;
};
template<class T1, class T2>
struct noncopy_pair: public std::pair<T1, T2>, private noncopy {
using std::pair<T1, T2>::pair;
};
template<class T1, class T2>
noncopy_pair<T1, T2> make_noncopy_pair(T1 &&t, T2 &&u);
int main() {
auto &&x = decltype(make_noncopy_pair(1, 'c'))(1, 'c');
}
К сожалению, вам нужно повторить свои аргументы, но вы можете использовать макрос, чтобы обойти это (и макрос по крайней мере гарантированно безопасен, поскольку ни один аргумент не оценивается более одного раза).