【问题标题】:Why should optional<T&> rebind on assignment?为什么 optional<T&> 应该在分配时重新绑定?
【发布时间】:2016-10-11 18:42:24
【问题描述】:

关于 optionalvariant 应该如何处理引用类型,尤其是在赋值方面,一直存在争论。我想更好地理解围绕这个问题的辩论。

optional<T&> opt;
opt = i;
opt = j; // should this rebind or do i=j?

目前,如果任何类型是引用类型,则决定将optional&lt;T&amp;&gt; 设置为格式错误,并将variant::operator= 设置为格式错误 - 回避参数并仍然为我们提供大部分功能。

opt = j应该重新绑定底层引用的论点是什么?换句话说,为什么我们应该像这样实现optional

template <class T>
struct optional<T&> {
    T* ptr = nullptr;

    optional& operator=(T& rhs) {
        ptr = &rhs;
        return *this;
    }
};

【问题讨论】:

  • 好吧,在你的例子中,如果opt = i 绑定一个引用,然后opt = j 通过引用分配,那不会觉得很奇怪吗?
  • 您几乎无法使用赋值绑定普通引用。
  • 如果opt 是作为函数参数进来的,那就特别奇怪了,这取决于在运行时opt = i; 是分配还是绑定
  • 我们已经将std::reference_wrapperauto ref = std::ref(i); ref = j; 重新绑定(由于非显式构造函数)。所以为了连贯性,重新绑定似乎更合乎逻辑。

标签: c++ reference optional c++17


【解决方案1】:

opt = j 应该重新绑定底层引用的论点是什么?

我不知道您要查找的“论据”是什么。但是您刚刚提出了“论据”:

optional<T&> opt;
opt = i;
opt = j;

现在,假设第二行和第三行相距很远。如果您只是阅读代码,您希望opt = j 做什么?或者更重要的是,您为什么期望它的行为与opt = i 不同?

如果包装器类型的行为完全基于其当前状态而有如此巨大的差异,那将是非常令人惊讶的。

此外,我们已经有一种方法可以传达您想要更改optional内部的值。即:*opt = j。这对optional&lt;T&amp;&gt;optional&lt;T&gt; 一样有效。

optional 的工作方式非常简单:它是一个包装器类型。像任何当前存在的包装器类型一样,对它们的操作会影响 包装器,而不是被包装的东西。为了影响被包装的东西,你明确地使用*-&gt; 或其他一些接口函数。

【讨论】:

  • 你的最后一段我觉得最引人注目 - 对包装器的操作会影响包装器。但其余的也都说得通。
  • 实际上,这是在不涉及引用的情况下,分配给已参与的可选时不使用类型 T 的运算符 = 的论据。
  • @ГригорийШуренков 笏?在这种情况下,operator= 应该做什么是毫无疑问的。它可能只意味着一件事。
  • 有两个相当不同的操作:'assign_value'(在引用的情况下将重新绑定引用)和在可选的 operator= 中使用的'reset_wrapper'。如果参数是对 optional 的操作应该影响 optional 的状态而不是其值的状态,则 operator = 唯一可能意味着'reset_wrapper' - 如果有一个,则完全销毁当前值,然后包装新值。
  • @ГригорийШуренков: 为optional 分配一个值就是说,“我希望可选项保持这个值。”如果可选项不包含任何对象,那么您希望将构造复制/移动到其中。如果可选项已经持有一个对象,那么您希望将分配复制/移动到已经持有的对象中,这样该对象现在将具有新值。无需销毁当前对象并创建一个新对象。 “destroy-and-copy-construct”和“copy-assign”之间没有有用的区别。当然除了性能,这就是我们做后者的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-25
  • 2012-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多