c++ 遍历std::variant的Map

x8diyxa7  于 5个月前  发布在  其他
关注(0)|答案(2)|浏览(120)

我正在尝试使用C++17的std::variant在map中存储多种类型的数据。这里的用例是拥有一个泛型类型的控制器的map(但由std::variant绑定),我可以遍历并调用其方法。在下面的示例中,

#include <iostream>
#include <map>
#include <variant>

class ControlA {
public:
    void specificToA() { std::cout << "A" << std::endl; }
};

class ControlB {
public:
    void specificToB() { std::cout << "B" << std::endl; }
};

template<typename T>
class ControlItem{
    T* control;

public:
    ControlItem() = default;
    ~ControlItem() = default;

    void doStuff() {
        if constexpr (std::is_same_v<T, ControlA>) {
            control->specificToA();
        }
        if constexpr (std::is_same_v<T, ControlB>) {
            control->specificToB();
        }
    }
};

class MyClass {
public:
    void cycleThroughMap();
    std::map<std::string, std::variant<ControlItem<ControlA>, ControlItem<ControlB>>> controlMap;
};

字符串
对此的启发式方法是获取每个声明类型的Map值,如:

void MyClass::cycleThroughMap() {
    for (auto controlItem : controlMap) {
        if (auto control = std::get_if<ControlItem<ControlA>>(&controlItem.second)) {
            control->doStuff();
         } else if (auto control = std::get_if<ControlItem<ControlB>>(&controlItem.second)) {
            control->doStuff();
         } else
            std::cout << "Unknown type!" << std::endl;
    }
}


这是可行的,但感觉就像它不应该存在。
std::variant可以用来做这个吗?从一开始就是个坏主意,我应该使用继承吗?

vmjh9lq9

vmjh9lq91#

std::variant可以用吗?
是的。你的代码已经准备好有效地使用一个变量。变量包含具有相同隐式接口的类型。这是一个将std::visit与泛型lambda一起使用的绝佳机会。

void MyClass::cycleThroughMap() {
    for (auto& [ key, control ] : controlMap) {
        std::visit([](auto& c) {
          c.doStuff();
        }, control);
    }
}

字符串
我还冒昧地用结构化绑定替换了pair访问。

sr4lhrrt

sr4lhrrt2#

另一种结构化代码的方法-删除了内联get_if. Comments的需要:

#include <map>
#include <variant>
#include <iostream>

class ControlA {
public:
    void specificToA() { std::cout << "A" << std::endl; }
};

// consistent free-function interface for each operation type allows ADL lookup
void adlDoStuff(ControlA& c)
{
    // but with different implementation details
    c.specificToA();
}

class ControlB {
public:
    void specificToB() { std::cout << "B" << std::endl; }
};

// consistent free-function interface for each operation type allows ADL lookup
void adlDoStuff(ControlB& c)
{
    // but with different implementation details
    c.specificToB();
}

template<typename T>
class ControlItem{
    T* control;

public:
    ControlItem() = default;
    ~ControlItem() = default;

    void doStuff() {
        // invoke the adl-friendly free functions.
        adlDoStuff(*control);
    }
};

class MyClass {
public:
    void cycleThroughMap();
    std::map<std::string, std::variant<ControlItem<ControlA>, ControlItem<ControlB>>> controlMap;
};

void MyClass::cycleThroughMap() {
    // use std::visit. Every type of control will have the .doStuff interface
    for (auto&& elem : controlMap) {
        std::visit([](auto&& control)
        {
            control.doStuff();
        }, elem.second);
    }
}

字符串

相关问题