#c #multithreading #concurrency #future
Вопрос:
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>());
Не могли бы вы объяснить, пожалуйста, почему? И каков рекомендуемый шаблон для создания фьючерсов для хранения полиморфных объектов?
Ответ №1:
Вы должны явно преобразовать результат 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
Ответ №2:
Возвращаемый тип вашей лямбды-a shared_ptr<Derived>
. Следовательно, будущее, которое async
будет создано, содержит shared_ptr<Derived>
А. Если вы хотите, чтобы у него был другой тип, вам нужно сделать возвращаемый тип лямбды правильным типом, static_pointer_cast
указав возвращаемое значение shared_ptr<Base>
.
auto f = std::async( [](){return std::static_pointer_cast<std::shared_ptr<Base>>std::make_shared<Derived>();});
Ответ №3:
Я бы настроил все так и чаще использовал ключевое слово auto. Фабрика животных выполняет все (неявное) приведение к базе (интерфейсу) для вас. Так что лямбда остается чище.
#include <type_traits>
#include <iostream>
#include <future>
//-----------------------------------------------------------------------------
// declare an interface/abstract baseclass for animals.
struct animal_itf
{
virtual ~animal_itf() = defau<
virtual void make_noise() = 0;
protected:
animal_itf() = defau<
};
//-----------------------------------------------------------------------------
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();
}