【问题标题】:boost optional recognizes inheritance?boost optional 承认继承?
【发布时间】:2016-05-18 14:09:12
【问题描述】:
class Base {};
class Derived : public Base {};

void func(boost::optional<Base>&) {}

int main () {
  boost::optional<Derived> x;
  func(x);
}

func 是否接受两个可选参数:base 和 derived?

【问题讨论】:

  • 在寻找其他东西时,我偶然发现了“通过成员模板强制”成语 (en.wikibooks.org/wiki/More_C%2B%2B_Idioms/…),它非常适合这种特殊情况。但是optional(不像shared_ptr 例如)不支持它。

标签: c++ boost boost-optional


【解决方案1】:

不,它不会起作用。 func 采用对 boost::optional&lt;Base&gt; 的左值引用。这意味着它可以接受boost::optional&lt;Base&gt; 类型的左值、公开且明确地从boost::optional&lt;Base&gt; 派生的类型的左值,或具有operator boost::optional&lt;Base&gt;&amp;() 的其他类型。对于boost::optional&lt;Derived&gt;,这些都不是真的。类模板在 C++ 类型系统中不是协变量的 - boost::optional&lt;Derived&gt; 不继承自 boost::optional&lt;Base&gt;


如果func 按价值来论证,那就另当别论了。如果它看起来像:

void func(boost::optional<Base> ) { }

在这种情况下,您可以使用boost::optional&lt;Derived&gt; 调用func。但是那个转换构造函数被标记为explicit,所以你必须写:

func(boost::optional<Base>{x});

这是明确的 - 你清楚地表明你正在(可能)切片x

【讨论】:

    【解决方案2】:

    即使它可以工作(这很可能是我没有检查过的),它也会导致切片。只有Base 部分会存储在可选中。

    可选的在内部保留一个存储Base所需大小的缓冲区。即使Base 的大小与Derived 相同(如您的情况),它仍然只会存储Base


    编辑:

    上面的答案是针对包含以下代码的原始问题给出的:

    int main () {
      boost::optional x(Derived());
      func(x);
    }
    

    这样的代码不正确有两个原因:

    1. boost::optional 需要模板参数
    2. 即使使用模板参数,它仍然是函数声明。

    我忽略了这些问题,并认为是这样的:

    int main () {
      boost::optional<Base> x = Derived();
      func(x);
    }
    

    虽然该代码确实可以编译(至少是 Visual Studio 2013 和 Boost 1.60)并导致切片。通过运行以下程序可以看出:

    #include <boost/optional.hpp>
    #include <iostream>
    
    class Base
    {
    public:
        virtual ~Base() { std::cout << "~Base" << std::endl; }
    };
    
    class Derived : public Base
    {
    public:
        virtual ~Derived() { std::cout << "~Derived" << std::endl; }
    };
    
    int main()
    {
        boost::optional<Base> x = Derived();
    }
    

    产生输出

    ~派生 ~基地 ~基地

    第二个~Base 表明optional 销毁Base 对象而不是Derived 对象。 (~Derived 和第一个 ~Base 一样来自临时对象 Derived()。)

    【讨论】:

    • 我对切片也有同样的想法,但我认为它可能是存储对可选值的引用而不是副本?
    • @mkmostafa 我已经编辑了我的答案以提供更多详细信息。并在您更改问题中的代码后解释原始答案。以某种方式改变了我的原始答案完全不正确......如果您想存储原始对象,您可以使用 mechanizm simialr 到 Boost.Any (Boost.Any 本身也不会有用)。可能 Boost.TypeErasure 已经有这样的东西了。
    猜你喜欢
    • 2021-02-18
    • 2022-01-13
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-19
    • 2011-06-17
    • 1970-01-01
    相关资源
    最近更新 更多