C++ boost::可选,不允许我重新分配常量值类型

C++ boost::可选,不允许我重新分配常量值类型,c++,boost,assignment-operator,const-correctness,boost-optional,C++,Boost,Assignment Operator,Const Correctness,Boost Optional,在我看来,boost::optional 可选=>持有可变的Foo,可以在初始化后重新分配 optional const=>包含一个const Foo,初始化后无法重新分配 optional const=>(应该?)持有可变的Foo,但在初始化后无法重新分配 可选=>(应该?)持有常量Foo,可以在初始化后重新分配 前两个案例按预期工作。但是,可选常量取消对常量Foo的引用,可选常量不允许在初始化后重新分配(如中所述) 常量值类型的重新分配就是我遇到的,错误是: /usr/include/b

在我看来,
boost::optional

  • 可选
    =>持有可变的Foo,可以在初始化后重新分配

  • optional const
    =>包含一个const Foo,初始化后无法重新分配

  • optional const
    =>(应该?)持有可变的Foo,但在初始化后无法重新分配

  • 可选
    =>(应该?)持有常量Foo,可以在初始化后重新分配

前两个案例按预期工作。但是,
可选常量
取消对常量Foo的引用,
可选常量
不允许在初始化后重新分配(如中所述)

常量值类型的重新分配就是我遇到的,错误是:

/usr/include/boost/optional/optional.hpp:486:错误:将'const Foo'作为'Foo&Foo::operator=(const Foo&)'的'this'参数传递将丢弃限定符[-fppermissive]

发生在这里:

void assign_value(argument_type val,is_not_reference_tag) { get_impl() = val; }
构造之后,该实现对您参数化可选对象的类型使用赋值运算符。它显然不想要一个常量值的左操作数。但为什么不能将非常量可选值重置为新的常量值,例如在本例中:

optional<Foo const> theFoo (maybeGetFoo());
while (someCondition) {

    // do some work involving calling some methods on theFoo
    // ...but they should only be const ones

    theFoo = maybeGetFoo();
}
可选theFoo(maybeGetFoo());
while(某些条件){
//做一些工作,包括在oo上调用一些方法
//…但它们应该是常量
theFoo=maybeGetFoo();
}
一些问题:

  • 我想这在概念上是好的,而不能做到这一点只是实现中的一个侥幸,这是对的吗

  • 如果我不编辑boost源代码,那么在不完全取消boost::optional的情况下,实现上述循环中的逻辑的干净方法是什么

  • 如果这是有意义的,并且我要编辑boost::可选源代码(我已经做过了,尽管我怀疑他们很快会自己做),那么什么微创更改可能会起作用呢


  • 因此,基本上问题似乎与for
    optional&optional::operator=(T const&rhs)
    中的注释有关:

    注意:如果*已初始化,则使用T的赋值运算符,否则使用其复制构造函数

    也就是说,假设您有
    boost::可选的theFoo。由于默认构造的
    boost::optional
    为空,因此语句:

    theFoo=defaultFoo;
    
    应该表示“将construct
    defaultFoo
    复制到
    theFoo
    s的内部存储中。”由于该内部存储中没有任何内容,因此这是有意义的,即使该内部存储应该容纳
    const Foo
    。完成后,
    foo
    将不会为空

    一旦foo
    包含一个值,语句

    theFoo=defaultFoo;
    
    应该表示“将
    defaultFoo
    分配到
    theFoo
    s内部存储中的对象中。”但是
    theFoo
    s内部存储是不可分配的(因为它是
    const
    ),因此这应该会引发(编译时?)错误

    不幸的是,您会注意到最后两条语句是相同的,但在概念上需要不同的编译时行为。不过,没有什么可以让编译器分辨出两者之间的区别


    特别是在您所描述的场景中,定义
    boost::optional
    的赋值运算符来代替语义可能更有意义:

    如果*已初始化,则首先销毁其当前内容。然后使用
    T
    的复制构造函数


    毕竟,如果你真的想调用
    T
    的赋值运算符,完全可以通过说
    *theFoo=rhs
    来回答你的三个问题:

  • 实现遵循optional的赋值使用T的赋值的设计思想;从这个意义上讲,实施是好的
  • 可选的设计考虑了可能的扩展。Optional只是基础类Optional\u base的接口。不使用optional,您可以从optional_基派生您自己的类。可选的_base有一个受保护的成员构造,它几乎满足您的需要。您将需要一个新成员,比如说reset(T),它首先清除可选的_基,然后调用construct()
  • 或者,您可以将成员重置(T)添加到可选。这将是干扰最小的变化
  • 您还可以尝试optional from的参考实现。

    (1)对行为“应该”是什么的看法取决于optionals是“零个或一个任意类型对象的容器”还是“一个类型的精简代理,具有附加功能”。现有的代码使用了后一种思想,通过这样做,它删除了列表中“四种不同行为”的一半。这降低了复杂性,并防止您无意中引入低效的使用

    (2)对于任何值可复制的
    Foo
    类型,可以通过创建一个新的选项轻松地在可变和不可变选项之间切换。因此,在给定的情况下,您可以简单地将其作为可变的,然后将其复制到一个不可变的值中

    optional<Foo> theMutableFoo (maybeGetFoo());
    while (someCondition) {
        optional<Foo const> theFoo (theMutableFoo);
    
        // do some work involving calling some methods on theFoo
        // ...but they should only be const ones
        // ...therefore, just don't use theMutableFoo in here!
    
        theMutableFoo = maybeGetFoo();
    }
    
    可选主题mutablefoo(maybeGetFoo());
    while(某些条件){
    可选的theFoo(主题为mutablefoo);
    //做一些工作,包括在oo上调用一些方法
    //…但它们应该是常量
    //…因此,不要在这里使用mutablefoo!
    theMutableFoo=maybeGetFoo();
    }
    
    考虑到它是一个类型的“精简代理”的模型,如果该类型没有封装在可选的。在这种情况下,普通常量值类型需要相同的处理

    (3)一个人会