C++ 遍历std::variant的映射

C++ 遍历std::variant的映射,c++,c++17,variant,C++,C++17,Variant,我正在试验用C++17在地图中存储多种类型的数据。这里的用例是有一个泛型类型的控制器的映射(但是由std::variant绑定),我可以遍历它并调用它的方法。 在下面的例子中 #include <iostream> #include <map> #include <variant> class ControlA { public: void specificToA() { std::cout << "A" << std::en

我正在试验用C++17在地图中存储多种类型的数据。这里的用例是有一个泛型类型的控制器的映射(但是由
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;
};
#包括
#包括
#包括
控制类{
公众:
void specificToA(){std::cout doStuff();
}否则
标准::cout
std::variant
可以用于此目的吗

是的。您的代码已经准备好有效地使用变体。变体包含具有相同隐式接口的类型。这是一个与通用lambda一起使用的绝佳机会

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

我还冒昧地用结构化绑定替换了pair访问。为了更加简单。

另一种构造代码的方法-不需要get_if。注释内联:

#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);
    }
}
#包括
#包括
#包括
控制类{
公众:

void specificToA(){std::cout如果你调用的是同一个函数,为什么要开始检查呢?你也可以通过将
specificTo
函数命名为相同的函数来取消签入
doStuff
。也许可以对
ControlA
ControlB
使用继承和多态性来给它们一个固定的接口?是的strai直接的方法就是,我正试图了解c++17的特性会给我的项目增加什么——感觉这个例子适合实验(尽管可能会因为它明显的多态性而混淆)[OT]<代码> t*控件;< /COD>未初始化。HA,正是我所要寻找的;这是C++初学者初学者不会想到的一些东西。完美无瑕,谢谢!
#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);
    }
}