15

UPDATE1: C++17 为构造函数添加了类型推导——这并不意味着 free 函数是一个劣质的解决方案。

UPDATE2: C++17 增加了保证复制省略(复制在概念上甚至不发生)。因此,使用 C++17,我的代码实际上可以工作并且具有最佳性能。但是我相信 Martinho 的代码使用大括号初始化返回值仍然是更干净的解决方案。但是请查看Barry 的这个答案和 TC 的评论

旧帖子:类型推导不适用于构造函数(至少在 C++11 之前并包括在内)。常见的解决方案是依靠 RVO(返回值优化),编写一个 make_XYZ 模板函数,将其参数转发给构造函数。一个例子是std::make_tuple

任何模板 acrobat 知道在 nocopy 策略妨碍时使这项工作正常工作的解决方法吗?一个有效的解决方案必须仍然允许 RVO 发生。

此外,任何 make_XYZ 的要求会随着 C++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;
}
4

2 回答 2

22

如果存在非显式构造函数,则确实可以按值返回不可复制和不可移动的类型。查看实时示例: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);
于 2013-10-17T13:26:50.837 回答
1

RVO 只是一种优化;从函数返回对象(临时或命名)时,复制/移动必须可用。

我建议make_XYZ在未评估的上下文中使用 only ,使用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');
}

不幸的是,您必须重复您的参数,但您可以使用宏来解决此问题(并且宏至少可以保证安全,因为没有参数被多次评估)。

于 2013-10-17T13:28:33.653 回答