以 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";
}
我想使用参数多态性编写一个采用不同类型方法指针的方法。我认为在这种情况下联合会是个好主意。但是,我不知道如何使用方法参数引用正确的联合实例。
#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";
}