这个问题的背景围绕着硬类型基因编程。
我想从一个函数返回一个函数指针,但是这些函数指针指向具有不同返回类型的函数。在另一个堆栈溢出问题(Function Pointers with Different Return Types C)中,提出了联合的返回类型,但是我正在为实现而苦苦挣扎。
我对C ++还是很陌生,所以请原谅我的无知。
#include <iostream>
#include <string>
float Add(float a, float b) { return a + b; }
bool IfElse(bool a) { if (a) { return true; } else { return false; }; }
union return_type
{
float(*ffptr)(float, float);
bool(*bfptr)(bool);
};
union fptr(std::string OPERATION) {
if (OPERATION == "Add") {
return_type.ffptr = Add;
} else if (OPERATION == "IfElse") {
return_type.bfptr = IfElse;
}
return return_type;
}
int main() {
std::cout << fptr("Add") << std::endl
return 0;
}
我希望(或更确切地说,希望这样做)打印添加功能的地址
答案 0 :(得分:4)
TL; DR版本:我认为您可能正在尝试hammer a solution into fitting a problem。考虑使用类似Visitor pattern的方法来解耦问题,这样您就不必知道数据的类型。
union
不是类型。 It's a type of types, like a class
or a struct
。为了使用return_type
,您必须制作一个return_type
的对象。那是
union fptr(std::string OPERATION) {
if (OPERATION == "Add") {
return_type.ffptr = Add;
} else if (OPERATION == "IfElse") {
return_type.bfptr = IfElse;
}
return return_type;
}
需要看起来更像
return_type fptr(std::string OPERATION) {
return_type result; // make a return_type object
if (OPERATION == "Add") {
result.ffptr = Add; // set a member of the object
} else if (OPERATION == "IfElse") {
result.bfptr = IfElse;
}
return result; // return the object
}
那么您可以
int main() {
std::cout << fptr("Add").ffptr(10,20) << std::endl; // call the stored function
return 0;
}
union
的最大问题是知道其中的内容。如果ffptr
是最后一个成员集,则只能安全使用ffptr
。
int main() {
std::cout << fptr("Add").bfptr(true) << std::endl;
return 0;
}
可以编译,但运行时表现不佳。会发生什么是不确定的,但是很有可能它不会很漂亮。
您必须绝对确定联合中存储的功能是正确的。如果您的编译器是最新的,请you can use std::variant
在此处提供帮助。至少会抛出异常,告诉您您的方向错误
#include <iostream>
#include <string>
#include <variant>
float Add(float a, float b) { return a + b; }
bool IfElse(bool a) { if (a) { return true; } else { return false; }; }
using return_type = std::variant<float (*)(float a, float b), bool (*)(bool a)>;
return_type fptr(std::string OPERATION) {
return_type result;
if (OPERATION == "Add") {
result = Add;
} else if (OPERATION == "IfElse") {
result = IfElse;
}
return result;
}
int main() {
std::cout << std::get<float (*)(float a, float b)>(fptr("Add"))(10,20) << std::endl;
try
{
std::cout << std::get<bool (*)(bool a)>(fptr("Add"))(true) << std::endl;
}
catch (const std::bad_variant_access& e)
{
std::cout << e.what() << std::endl;
}
return 0;
}
但是最终还是没有那么有用。我认为您可能会发现Visitor pattern或它的一个朋友更有用。
答案 1 :(得分:2)
你很近。 注意不要将(联合)类型名称的声明和函数返回值混淆。由于您要引用指针地址,因此我在您的联合(fpaddr)中添加了一个void *,因此您可以清楚地识别出您正在打印地址。请注意,您的fptr(“ Add”)返回了联合,并且您需要消除对所需联合的解释的歧义。
#include <iostream>
#include <string>
float Add(float a, float b) { return a + b; }
bool IfElse(bool a) { if (a) { return true; } else { return false; }; }
//typedef //in C you would use 'typedef'
union fp_return_t
{
float(* ffptr )(float, float);
bool(* bfptr )(bool);
void* fpaddr;
}; //fp_return_t; //in C you would give the name here
fp_return_t fptr(std::string OPERATION) {
fp_return_t fp_return;
if (OPERATION == "Add") {
std::cout << "Add:" << (void*) Add << std::endl;
fp_return.ffptr = Add;
} else if (OPERATION == "IfElse") {
std::cout << "IfElse:" << (void*) IfElse << std::endl;
fp_return.bfptr = IfElse;
}
return fp_return;
}
int main() {
std::cout << fptr("Add").fpaddr << std::endl;
return 0;
}
答案 2 :(得分:1)
我不确定最终目标是什么,但是您可以通过以下方法进行上述编译并打印函数地址(打印出普通的Add
以供比较):
#include <iostream>
#include <string>
float Add(float a, float b) { return a + b; }
bool IfElse(bool a) { return a; }
union return_type
{
float(*ffptr)(float, float);
bool(*bfptr)(bool);
};
union return_type fptr(std::string OPERATION) {
union return_type r;
if (OPERATION == "Add") {
r.ffptr = Add;
} else if (OPERATION == "IfElse") {
r.bfptr = IfElse;
}
return r;
}
int main()
{
/*the void*-cast is technically nonportable but it's hard to
print fn-pointers portably*/
std::cout << reinterpret_cast<void*>(Add) << '\n';
/*you should know which union member is active: */
std::cout << reinterpret_cast<void*>(fptr("Add").ffptr) << '\n';
/*^should be the same address*/
return 0;
}