c++ 遍历std::variant的Map

x8diyxa7  于 2024-01-09  发布在  其他
关注(0)|答案(2)|浏览(202)

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

  1. #include <iostream>
  2. #include <map>
  3. #include <variant>
  4. class ControlA {
  5. public:
  6. void specificToA() { std::cout << "A" << std::endl; }
  7. };
  8. class ControlB {
  9. public:
  10. void specificToB() { std::cout << "B" << std::endl; }
  11. };
  12. template<typename T>
  13. class ControlItem{
  14. T* control;
  15. public:
  16. ControlItem() = default;
  17. ~ControlItem() = default;
  18. void doStuff() {
  19. if constexpr (std::is_same_v<T, ControlA>) {
  20. control->specificToA();
  21. }
  22. if constexpr (std::is_same_v<T, ControlB>) {
  23. control->specificToB();
  24. }
  25. }
  26. };
  27. class MyClass {
  28. public:
  29. void cycleThroughMap();
  30. std::map<std::string, std::variant<ControlItem<ControlA>, ControlItem<ControlB>>> controlMap;
  31. };

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

  1. void MyClass::cycleThroughMap() {
  2. for (auto controlItem : controlMap) {
  3. if (auto control = std::get_if<ControlItem<ControlA>>(&controlItem.second)) {
  4. control->doStuff();
  5. } else if (auto control = std::get_if<ControlItem<ControlB>>(&controlItem.second)) {
  6. control->doStuff();
  7. } else
  8. std::cout << "Unknown type!" << std::endl;
  9. }
  10. }


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

vmjh9lq9

vmjh9lq91#

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

  1. void MyClass::cycleThroughMap() {
  2. for (auto& [ key, control ] : controlMap) {
  3. std::visit([](auto& c) {
  4. c.doStuff();
  5. }, control);
  6. }
  7. }

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

sr4lhrrt

sr4lhrrt2#

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

  1. #include <map>
  2. #include <variant>
  3. #include <iostream>
  4. class ControlA {
  5. public:
  6. void specificToA() { std::cout << "A" << std::endl; }
  7. };
  8. // consistent free-function interface for each operation type allows ADL lookup
  9. void adlDoStuff(ControlA& c)
  10. {
  11. // but with different implementation details
  12. c.specificToA();
  13. }
  14. class ControlB {
  15. public:
  16. void specificToB() { std::cout << "B" << std::endl; }
  17. };
  18. // consistent free-function interface for each operation type allows ADL lookup
  19. void adlDoStuff(ControlB& c)
  20. {
  21. // but with different implementation details
  22. c.specificToB();
  23. }
  24. template<typename T>
  25. class ControlItem{
  26. T* control;
  27. public:
  28. ControlItem() = default;
  29. ~ControlItem() = default;
  30. void doStuff() {
  31. // invoke the adl-friendly free functions.
  32. adlDoStuff(*control);
  33. }
  34. };
  35. class MyClass {
  36. public:
  37. void cycleThroughMap();
  38. std::map<std::string, std::variant<ControlItem<ControlA>, ControlItem<ControlB>>> controlMap;
  39. };
  40. void MyClass::cycleThroughMap() {
  41. // use std::visit. Every type of control will have the .doStuff interface
  42. for (auto&& elem : controlMap) {
  43. std::visit([](auto&& control)
  44. {
  45. control.doStuff();
  46. }, elem.second);
  47. }
  48. }

字符串

展开查看全部

相关问题