C++ 为什么std::variant中禁止引用?
我经常使用C++ 为什么std::variant中禁止引用?,c++,boost,c++17,variant,C++,Boost,C++17,Variant,我经常使用boost::variant,对它非常熟悉boost::variant不以任何方式限制有界类型,特别是它们可能是引用: #include <boost/variant.hpp> #include <cassert> int main() { int x = 3; boost::variant<int&, char&> v(x); // v can hold references boost::get<int>(
boost::variant
,对它非常熟悉boost::variant
不以任何方式限制有界类型,特别是它们可能是引用:
#include <boost/variant.hpp>
#include <cassert>
int main() {
int x = 3;
boost::variant<int&, char&> v(x); // v can hold references
boost::get<int>(v) = 4; // manipulate x through v
assert(x == 4);
}
基本上,
optional
和variant
不允许引用类型的原因是,对于这种情况下的赋值(以及在较小程度上的比较)应该做什么,存在分歧<代码>可选比变体
更容易在示例中显示,因此我将坚持这一点:
int i = 4, j = 5;
std::optional<int&> o = i;
o = j; // (*)
文件提供了这一基本原理:
重新初始化初始化可选引用的重新绑定语义被选择为在初始化状态之间提供<强>一致性,甚至以与裸C++引用的语义缺乏一致性为代价。确实,
optional
努力在初始化时尽可能地表现出U的行为;但是在U
为T&
的情况下,这样做会导致w.r.T与左值初始化状态不一致
想象>代码>可选< /COD>转发给引用对象的分配(从而改变引用的对象值但不重新绑定),并考虑以下代码:
optional<int&> a = get();
int x = 1 ;
int& rx = x ;
optional<int&> b(rx);
a = b ;
在这一行应该做什么方面缺乏一致意见意味着完全不允许引用更容易,因此,
optional
和variant
的大部分值至少可以用于C++17并开始有用。引用总是可以在以后添加的——或者说是这样 一个cast或std::get(v).get()
,公平地说。你可以使用指针,尽管没有与可选的相同问题:你是通过引用赋值还是重新放置引用?@Galik在我的应用程序中,我可以使用指针,但我必须编写大量额外的代码。我有很多boost::get
调用,如果变量包含完整类型或引用,这些调用可以无缝工作。它不能与指针无缝地工作。对不起,应该说boost::get
和boost::apply\u visitor
调用。我可以简单地包装第一个以无缝地处理指针,但包装第二个并不容易。解释是有道理的,谢谢。不过,作为一个天真的用户,我希望我的变体的行为与它当前持有的类型完全相同。我不能重新绑定引用,所以我不希望variant在赋值时重新绑定。“重新绑定是一个更合理的实现,是您真正想要的”我猜您的意思是“您”,而不是我个人,因为我不希望它重新绑定。@olq\u plo我同意天真的期望是optional
确实通过赋值。但对于那种类型来说,这是一个糟糕的选择。请注意,boost::optional
。尽管对于variant来说,这是一个合理的选择,所以我可能不应该强迫optional和variant行为相似。@olq\u plo我不同意(a)这是variant的合理选择,(b)optional和variant有意义的不同。如果optional
与variant
具有不同的语义,那将非常混乱
// rebind
o.emplace(j);
// assign through
if (o) {
*o = j;
} else {
o.emplace(j);
}
optional<int&> a = get();
int x = 1 ;
int& rx = x ;
optional<int&> b(rx);
a = b ;
assert(!!opt);
*opt=value;