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>();});
}
This gives the following error :
error: conversion from 'future<shared_ptr<Derived>>' to non-scalar type 'future<shared_ptr<Base>>' requested
However, this compiles :
std::promise<std::shared_ptr<Base>> p;
std::future<std::shared_ptr<Base>> f = p.get_future();
p.set_value(std::make_shared<Derived>());
Could you please explain why? And what is the recommended pattern to create futures to hold polymorphics objects?
CodePudding user response:
You must explicitly convert the result of make_shared<Derived>()
into a 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
CodePudding user response:
The return type of your lambda is a shared_ptr<Derived>
. Therefore, the future that async
will create contains a shared_ptr<Derived>
. If you want it to have a different type, you need to make the lambda's return type the correct type, by static_pointer_cast
ing the return value to shared_ptr<Base>
.
auto f = std::async( [](){return std::static_pointer_cast<std::shared_ptr<Base>>std::make_shared<Derived>();});
CodePudding user response:
I would set things up like this and make more use of the auto keyword. The animal factory does al the (implicit) casting to base (interface) for you. So the lambda stays cleaner.
#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();
}