construction helper make_XYZ allowing RVO and type deduction even if XZY has noncopy constraint

╄→尐↘猪︶ㄣ 提交于 2019-11-28 07:38:59

If there is a non-explicit constructor, it is indeed possible to return a non-copiable and non-movable type by value. See live example: http://coliru.stacked-crooked.com/a/89ef9d3115924558.

template <typename T>
XYZ<T> make_XYZ (T && i)
{
    return { std::forward<T>(i) };
}

The tricky bit here is that { ... } is not constructing a temporary and moving it to the return value. It is directly initialising the return value. There is no copy nor move, and that is irrelevant of whether any optimisation applies (it wouldn't compile if it required an optimisation to work).

However, since the type is not copyable nor movable, you will not be able to store it in a local variable by value. You can, however, use the old temporary lifetime extension trick to hold it:

auto&& x = make_XYZ(1);

RVO is only ever an optimisation; the copy/move has to be available for use when returning an object (temporary or named) from a function.

I'd suggest using the make_XYZ only in a nonevaluated context, using 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');
}

Unfortunately you have to repeat your arguments, but you can use a macro to work around this (and the macro is at least guaranteed safe, as no argument is evaluated more than once).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!