不能使用 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();
}
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();
}