如何访问`std::variant`的任何孩子的`polymorphic`基类?

Posted

技术标签:

【中文标题】如何访问`std::variant`的任何孩子的`polymorphic`基类?【英文标题】:How to access the `polymorphic` base class for any child of an `std::variant`? 【发布时间】:2019-10-06 09:53:15 【问题描述】:

假设一个基类有几个子类:

class Base 

public:
    void printHello() const  cout << "Hello" << endl; 
;

class Child1: public Base ;
class Child2: public Base ;
class Child3: public Base ;
..
class ChildN: public Base ;

假设一个变体包含任何包含的类:

using MyVariant = std::variant<Base, Child1, Child2, Child3, ... ChildN>;

注意:这个的兴趣(相比于一个简单的多态向量 指针),是将所有数据放在同一个内存数组中,因为 它们将被转移到设备上。在这种情况下,真正的 每个对象的内容都在向量中,而不仅仅是指向某些对象的指针 heap 位置。

最后,假设我想使用vector&lt;MyVariant&gt; 的每个元素的Base 多态版本。

std::vector<MyVariant> myVariantList;
... // Initialization

for (const MyVariant& elem: myVariantList)

    const Base* baseElem = get_if_polymorph<Base>(elem); //HOW TO?
    baseElem->printHello();

注意:显然,为每种类型添加if 语句的简单解决方案不是意图,因为可以将新的子类添加到MyVariant无需更改所有进一步的用法。 (可扩展性)

所以另一种表达问题的方式是:

如何管理 std::variant 中的多态性?

【问题讨论】:

非常好的问题。谢谢。 【参考方案1】:

std::visit 与通用 lambda 一起使用:

const Base& baseElem = std::visit(
    [](const auto& x) -> const Base&  return x; ,
    elem);

最小的可重现示例:

#include <iostream>
#include <variant>
#include <vector>

struct Base 
    virtual void hi() const
    
        std::cout << "Base\n";
    
;

struct Derived1 : Base 
    void hi() const override
    
        std::cout << "Derived1\n";
    
;

struct Derived2 : Base 
    void hi() const override
    
        std::cout << "Derived2\n";
    
;

int main()

    using Var = std::variant<Base, Derived1, Derived2>;
    std::vector<Var> elems;
    elems.emplace_back(std::in_place_type<Base>);
    elems.emplace_back(std::in_place_type<Derived1>);
    elems.emplace_back(std::in_place_type<Derived2>);
    for (const auto& elem : elems) 
        const Base& x = std::visit(
            [](const auto& x) -> const Base&  return x; ,
            elem);
        x.hi();
    

输出:

Base
Derived1
Derived2

(live demo)

【讨论】:

以上是关于如何访问`std::variant`的任何孩子的`polymorphic`基类?的主要内容,如果未能解决你的问题,请参考以下文章

使用类作为数据类型时如何在 std::variant 中存储值?

std::get_if (std::variant) 通过指针而不是值/&/const& 获取变体参数是不是有任何实际原因?

std::visit 无法推断 std::variant 的类型

如何将 std::variant 作为 VARIANT* 传递给 ExecWB?

如何将 boost::hana::tuple 转换为 std::variant

如何在编译时捕获 std::variant 持有错误类型?