为什么std::optional
(目前 libc ++ 中的std::experimental::optional
)没有针对参考类型的专业化(与boost::optional
相比)?
我认为这将是非常有用的选择。
STL 中是否存在引用可能已存在的对象语义的对象?
答案 0 :(得分:15)
当讨论n3406(提案的第2版)时,一些委员会成员对可选参考文献感到不舒服。在n3527(修订版#3)中,作者决定将可选引用作为辅助提议,以增加获得可选值的可能性并将其置于C ++ 14中。虽然由于各种其他原因,可选项并未完全进入C ++ 14,但委员会并未拒绝可选引用,如果有人提出,可以在将来自由添加可选引用。
答案 1 :(得分:6)
确实存在引用可能现有对象语义的内容。它被称为(const)指针。一个普通的旧非拥有指针。引用和指针之间有三个不同之处:
std::optional
避免的差异。->
或*
取消引用。这是纯粹的语法糖,可能因为1.并且指针语法(解除引用和转换为bool)正是std::optional
为访问值并测试其存在所提供的。 <强>更新强>
optional
是值的容器。与其他容器(例如vector
)一样,设计不包含引用。如果你想要一个可选的引用,使用一个指针,或者如果你确实需要一个与std::optional
具有类似语法的接口,那么为指针创建一个小的(和普通的)包装器。
更新2:至于问题为什么没有这样的专业化:因为委员会只是选择了它。 的基本原理可能可以在论文的某处找到。这可能是因为他们认为指针足够了。
答案 2 :(得分:4)
std::optional <T&>
的主要问题是-在以下情况下optRef = obj
应该做什么:
optional<T&> optRef;
…;
T obj {…};
optRef = obj; // <-- here!
变量:
(&optRef)->~optional(); new (&optRef) optional<T&>(obj)
。*optRef = obj
(在!optRef
之前为UB)进行分配。if (optRef) {do1;} else {do2;}
。每个变体的优点:
始终重新绑定(由boost::optional和n1878选择):
!optRef
和optRef.has_value()
—后置条件&*optRef == &obj
的情况之间的一致性。optional<T>
保持一致:对于通常的optional<T>
,如果将T::operator=
定义为破坏和构造(并且有人认为它必须是 只是破坏和构造的优化),opt = …
实际上 的行为类似于(&opt)->~optional(); new (&opt) optional<T&>(obj)
。分配方式:
T&
的一致性:对于纯T&
,ref = …
分配通过(不重新绑定ref
)。optional<T>
保持一致:对于通常的optional<T>
,当opt.has_value()
时,opt = …
被要求分配通过,而不是破坏和构造(参见n3672和on cppreference.com中的template <class U> optional<T>& optional<T>::operator=(U&& v)
。optional<T>
保持一致:两者都至少以某种方式定义了operator=
。如果为空则绑定,否则进行赋值-我看不出任何真正的好处,恕我直言,只有当#1的支持者与#2的支持者争论时,该变体才会出现,但是从形式上讲,它与{ {1}}(恕我直言,恕我直言)。
没有赋值运算符(由n3406选择):
template <class U> optional<T>& optional<T>::operator=(U&& v)
保持一致:纯T&
不允许重新绑定自身。另请参阅:
答案 3 :(得分:0)
如果我冒险猜测,那将是因为std :: experimental :: optional规范中的这句话。 (第5.2节,第1节)
需要实例化模板
optional
的程序 对于引用类型,或者可能是cv限定类型in_place_t
或nullopt_t
格式不正确。
答案 4 :(得分:0)
恕我直言,可以使用std::optional<T&>
。但是,模板存在一个微妙的问题。如果有引用,模板参数可能会变得难以处理。
就像我们解决模板参数中的引用问题一样,我们可以使用std::reference_wrapper
来避免缺少std::optional<T&>
。因此现在它变成std::optional<std::reference_wrapper<T>>
。但是,我建议您反对这种用法,因为1)写签名(返回返回类型为我们节省了一点时间)和签名的使用(我们必须调用std::reference_wrapper<T>::get()
以获得真正的参考)太冗长了,和2)大多数程序员已经被指针折磨了,这就像本能的反应,当他们收到一个指针时,他们首先会测试它是否为空,所以现在不再是一个大问题了。