类模板如何存储引用或值? [英] How can a class template store either reference or value?
问题描述
关于通用参考书的阅读导致了我想知道:如何构造一个类模板,以便在可能的情况下按引用存储,或者在必要时按值存储?
Reading about universal references led me to wonder: how can I construct a class template such that it stores by reference if possible, or by value if it must?
也就是说,我可以这样做吗?
That is, can I do something like this
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()
是给定左值的所有者将持有一个引用,当给定 rvalue 的所有者将进行复制吗?
Except that when hold_this()
is given an lvalue the holder will hold a reference, and when given an rvalue the holder will make a copy?
推荐答案
除了为hold_this()赋予左值时,持有人将持有引用,而给与右值时,持有人将进行复制吗?
Except that when hold_this() is given an lvalue the holder will hold a reference, and when given an rvalue the holder will make a copy?
您已经编写了它(减去必需的模板< typename T>
)。 转发参考的扣除规则保留值类别如下:
You already wrote it (minus the required template <typename T>
). The deduction rules for a forwarding reference preserve value category as follows:
- 如果
t
绑定到类型为T2
的左值,然后T = T2&
。 - 如果
t
绑定到类型为T2
的右值,则T = T2
。
- If
t
is bound to an lvalue of typeT2
, thenT = T2&
. - If
t
is bound to an rvalue of typeT2
, thenT = T2
.
上面的意思是您直接用 holder
实例化 holder
在右值情况下为 T2
。给您您想要的。制作副本。
The above means that you instantiate holder
directly with T2
in the rvalue case. Giving you exactly what you want. A copy is made.
事实上,制作了两个副本。一次创建构造函数自变量 t
,另一个副本是从中初始化 obj_m
。但是我们可以通过巧妙地使用type_traits来摆脱它:
As a matter of fact, two copies are made. Once to create the constructor argument t
, and the other copy is to initialize obj_m
from it. But we can get rid of it with some clever use of 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< T>(t)}
解析为初始化 obj_m
来自正确的引用类型。
See it live. We use add_rvalue_reference_t
to make t
be of the correct reference type in each case. And "simulate" the argument deduction which would make obj_m { std::forward<T>(t) }
resolve to initializing obj_m
from the correct reference type.
我说模拟是因为了解 holder $ c $的构造函数参数很重要c>不能是转发引用,因为构造函数本身没有模板。
I say "simulate" because it's important to understand the constructor argument for holder
cannot be a forwarding reference because the constructor itself is not templated.
顺便说一句,因为标记了 c ++ 17 ,我们也可以在您的示例中添加演绎指南。如果我们定义如下(来自 TC 的反馈):
By the way, since you tagged c++17, we can also add a deduction guide to your example. If we define it as follows (with the feedback from 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()};
,其推导类型与函数以前返回的值相同。
Then this live example shows you can define variables as hold h1{t};
and hold h2{test()};
, with the same deduced types as the function return values from before.
这篇关于类模板如何存储引用或值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!