以 union 作为方法参数

Taking union as a method parameter

我想使用参数多态性编写一个采用不同类型方法指针的方法。我认为在这种情况下联合会是个好主意。但是,我不知道如何使用方法参数引用正确的联合实例。

#include <iostream>

union Method {
  struct {
    void (*a)();
    void (*b)(int);
  };
};

struct Item {
  char c;
  Method m;
};

int8_t menu_size = 0;
void add_item(Item menu[], Item item) {
  int8_t index = 0;
  bool exists = false;
  do {
    if (menu[index].c == item.c) exists = true;
    ++index;
  } while (menu[index].c == item.c);
  //
  if (exists) {
    menu[index - 1] = item;
  } else {  
    menu[menu_size] = item;
    ++menu_size;
  }
}

void hello();
void ret(int);

int main(void) {
  Item menu[2];

  add_item(menu, (Item){'h', &hello});
  add_item(menu, (Item){'r', &ret});

  menu[0].m();
  menu[1].m(5);

  return 0;
}

void hello() {
  std::cout << "Hello, World!\n";
}

void ret(int i) {
  std::cout << i << "\n";
}

你是对的,你“不知道如何引用正确的联合实例”。工会就是这样运作的。联合没有任何内容表明联合成员的哪个实例是已设置的。必须使用其他一些带外机制来跟踪它,您有责任实施它,并手动记录或跟踪您设置的联合成员。某处的其他一些变量或标志,其值指示设置了哪个联合成员。当然,这不是唯一的方法,但却是最简单的方法。在任何情况下,您都有责任在这里正确跟踪所有内容。工作量很大。

此外,C++ 继承了 C 的联合,而 C 没有 类。而且,在 C++ 中,包含 类 的联合有更多的限制和陷阱,这确实带来了比它们值得的更多的麻烦。

幸运的是,使用现代 C++,您将始终使用 std::variants 而不是 union,它解决了所有这些问题,并为您完成所有艰苦的工作以确保 union 中的所有内容都是正确完成,类型安全。

作为 std::variant 用法的示例:

#include <iostream>
#include <variant>

struct Item {
  char c;
  std::variant<void (*)(), void (*)(int)> method;
};

int8_t menu_size = 0;
void add_item(Item menu[], Item item) {
  int8_t index = 0;
  bool exists = false;
  do {
    if (menu[index].c == item.c) exists = true;
    ++index;
  } while (menu[index].c == item.c);
  //
  if (exists) {
    menu[index - 1] = item;
  } else {  
    menu[menu_size] = item;
    ++menu_size;
  }
}

void hello();
void ret(int);

int main(void) {
  Item menu[2];

  add_item(menu, (Item){'h', &hello});
  add_item(menu, (Item){'r', &ret});

  std::get<void(*)()>(menu[0].method)();
  std::get<void(*)(int)>(menu[1].method)(5);

  return 0;
}

void hello() {
  std::cout << "Hello, World!\n";
}

void ret(int i) {
  std::cout << i << "\n";
}