阅读有关通用引用的内容使我产生了疑问:我如何构造一个类模板,使它能够在可能的情况下按引用存储,或者在必须的情况下按值存储?
那就是,我可以做这样的事情吗
template <class T>
class holder {
T obj_m; // should be a reference if possible...
public:
holder(T t) :obj_m { t } {}
}
auto
hold_this(T && t) { return holder<T>(t); }
除了当hold_this()
被赋予L值时,持有者将持有引用,而当被赋予R值时,持有者将复制?
除了当给hold_this()一个L值时,持有者将持有一个引用,而当给出一个R值时,持有者将制作一个副本?
您已经编写了它(减去所需的模板
)。 转发参照保值类别的扣减规则如下:
T
绑定到T2
类型的L值,则T=T2&
。T
绑定到T2
类型的rvalue,则T=T2
。std::forward
依靠这些演绎规则来完成工作。 以及为什么我们还需要将类型传递给它。
上面的意思是在rvalue的情况下直接用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)); }
看现场直播。 我们使用add_rvalue_reference_t
使t
在每种情况下都具有正确的引用类型。 并“模拟”参数推导,使OBJ_M{std::forward
解析为从正确的引用类型初始化OBJ_M
。
我说“模拟”是因为理解构造函数参数非常重要,holder
不能是转发引用,因为构造函数本身没有模板化。
顺便说一下,既然你给C++17加了标签,我们也可以给你的例子添加一个演绎指南。 如果我们将其定义如下(根据T.C.incorporated的反馈):
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>;
然后,这个实际示例显示,您可以将变量定义为hold h1{t};
和hold h2{test()};
,其推导类型与之前的函数返回值相同。