TL;DR version: I think you may be trying to hammer a solution into fitting a problem. Consider using something like the Visitor pattern to decouple the problem so that you don't need to know the type of the data.
A union
isn't a type. It's a type of types, like a class
or a struct
. In order to use a return_type
, you have to make an object that is a return_type
. That means
union fptr(std::string OPERATION) {
if (OPERATION == "Add") {
return_type.ffptr = Add;
} else if (OPERATION == "IfElse") {
return_type.bfptr = IfElse;
}
return return_type;
}
needs to look more like
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
}
Then you can
int main() {
std::cout << fptr("Add").ffptr(10,20) << std::endl; // call the stored function
return 0;
}
The big problem with union
s is knowing what is in them. You can only safely use ffptr
if ffptr
was the last member set.
int main() {
std::cout << fptr("Add").bfptr(true) << std::endl;
return 0;
}
will compile, but will not behave well at all when run. What will happen is undefined, but odds are good that it won't be pretty.
You have to be absolutely certain that the function stored in the union is the correct one. If your compiler is up to date, you can use std::variant
to help out here. It will at least tell you you're headed in the wrong direction by throwing an exception
#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;
}
But at the end of the day it's still not all that useful. I think you may find the Visitor pattern or one of its friends more helpful.