Подтвердить что ты не робот

Строительный помощник 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;
}
4b9b3361

Ответ 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');
}

К сожалению, вам нужно повторить свои аргументы, но вы можете использовать макрос, чтобы обойти это (и макрос по крайней мере гарантированно безопасен, поскольку ни один аргумент не оценивается более одного раза).