不能使用 std::future 来存储多态对象

Cannot use std::future to store polymorphic object

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>());

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

您必须明确地将 make_shared<Derived>() 的结果转换为 shared_ptr<Base>:

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

您的 lambda 的 return 类型是 shared_ptr<Derived>。因此,async 将创造的未来包含一个 shared_ptr<Derived>。如果您希望它具有不同的类型,则需要通过 static_pointer_cast 将 return 值设为 shared_ptr<Base>.[=16 来使 lambda 的 return 类型正确=]

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

我会这样设置并更多地使用 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();
}