【问题标题】:Cannot use std::future to store polymorphic object不能使用 std::future 存储多态对象
【发布时间】:2021-11-14 07:23:59
【问题描述】:
struct Base {
    virtual void squawk () {
        std::cout << " I am base" << std::endl;
    }
};

struct Derived : public Base {
    void squawk () override {
        std::cout << "I am derived" << std::endl;
    }
};

int main () {
    std::future<std::shared_ptr<Base>> f = std::async([](){return std::make_shared<Derived>();});
}

这会产生以下错误:

error: conversion from 'future<shared_ptr<Derived>>' to non-scalar type 'future<shared_ptr<Base>>' requested

但是,这可以编译:

std::promise<std::shared_ptr<Base>> p;
std::future<std::shared_ptr<Base>> f = p.get_future();
p.set_value(std::make_shared<Derived>());

你能解释一下为什么吗?以及创建保存多态对象的期货的推荐模式是什么?

【问题讨论】:

    标签: c++ multithreading concurrency future


    【解决方案1】:

    我会这样设置并更多地使用 auto 关键字。 动物工厂为您完成所有(隐式)转换为基础(界面)。 所以 lambda 保持清洁。

    #include <type_traits>
    #include <iostream>
    #include <future>
    
    //-----------------------------------------------------------------------------
    // declare an interface/abstract baseclass for animals.
    
    struct animal_itf
    {
        virtual ~animal_itf() = default;
        virtual void make_noise() = 0;
    
    protected:
        animal_itf() = default;
    };
    
    //-----------------------------------------------------------------------------
    
    struct bear_t final :
        public animal_itf
    {
        void make_noise() override
        {
            std::cout << "I am a bear : GROWL" << std::endl;
        }
    };
    
    struct cat_t final :
        public animal_itf
    {
        void make_noise() override
        {
            std::cout << "I am a cat : Meow" << std::endl;
        }
    };
    
    //-----------------------------------------------------------------------------
    // animal factory
    
    template<typename animal_t> 
    std::shared_ptr<animal_itf> make_animal()
    {
        return std::make_shared<animal_t>();
    }
    
    //-----------------------------------------------------------------------------
    
    int main()
    {
        auto future = std::async(std::launch::async, [](){ return make_animal<cat_t>(); });
    
        // show that the auto type IS a future holding a std::shared_ptr<animal_itf>
        static_assert(std::is_same_v<std::future<std::shared_ptr<animal_itf>>, decltype(future)>);
    
        auto animal_itf = future.get();
        animal_itf->make_noise();
    }
    

    【讨论】:

      【解决方案2】:

      您的 lambda 的返回类型是 shared_ptr&lt;Derived&gt;。因此,async 将创建的未来包含一个shared_ptr&lt;Derived&gt;。如果您希望它具有不同的类型,则需要通过static_pointer_casting 将返回值设置为shared_ptr&lt;Base&gt;,使 lambda 的返回类型正确。

      auto f = std::async( [](){return std::static_pointer_cast<std::shared_ptr<Base>>std::make_shared<Derived>();});
      

      【讨论】:

        【解决方案3】:

        您必须将make_shared&lt;Derived&gt;() 的结果显式转换为shared_ptr&lt;Base&gt;

        std::future<std::shared_ptr<Base>> f = std::async( [](){
            return std::shared_ptr<Base> {std::make_shared<Derived>()};
        });
        
        // or
        
        std::future<std::shared_ptr<Base>> f = std::async( []() -> std::shared_ptr<Base> {
            return std::make_shared<Derived>();
        });
        
        f.get()->squawk(); // I am derived
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-05-22
          • 1970-01-01
          • 2019-09-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-06-02
          相关资源
          最近更新 更多