除了当hold_this()被赋予一个左值时持有者将持有一个引用,而当给定一个右值时持有者将进行复制?
你已经写好了(减去所需的template <typename T>)。 转发引用保留值类别的扣除规则如下:
- 如果
t 绑定到T2 类型的左值,则T = T2&。
- 如果
t 绑定到T2 类型的右值,则T = T2。
std::forward 依靠这些推理规则来完成工作。以及为什么我们还需要将类型传递给它。
上面的意思是你在右值的情况下直接用T2实例化holder。给你你想要的。已制作副本。
事实上,制作了两份副本。一次创建构造函数参数t,另一个副本是从它初始化obj_m。但是我们可以通过巧妙地使用 type_traits 来摆脱它:
template <class T>
class holder {
T obj_m; // should be a reference if possible...
public:
holder(std::add_rvalue_reference_t<T> t) :obj_m { std::forward<T>(t) } {}
};
template<typename T>
auto hold_this(T && t) { return holder<T>(std::forward<T>(t)); }
See it live。我们使用add_rvalue_reference_t 使t 在每种情况下都具有正确的引用类型。并“模拟”使obj_m { std::forward<T>(t) } 解析为从正确的引用类型初始化obj_m 的参数推导。
我说“模拟”是因为理解 holder 的构造函数参数不能是转发引用很重要,因为构造函数本身没有模板化。
顺便说一句,既然你标记了c++17,我们还可以在你的例子中添加一个演绎指南。如果我们将其定义如下(并入feedback from T.C.):
template <class T>
class holder {
T obj_m; // should be a reference if possible...
public:
holder(T&& t) :obj_m { std::forward<T>(t) } {}
};
template<typename T>
holder(T&&) -> holder<T>;
然后this live example 显示您可以将变量定义为hold h1{t}; 和hold h2{test()};,其推导类型与之前的函数返回值相同。