Reputation: 3789
I have a table of functions. It looks something like this:
struct AnimalFunction {
void (*Walk)(int a);
void (*Sing)(int a, int b);
void (*Dance)(int a, int b, int c);
};
using AnimalFunctionTable = map<string, AnimalFunction>;
In other words, I have rows of AnimalFunction
's and a map from some string that I know to, essentially, a type. For simplicity, maybe I include some extra arguments so that they all have the same signature and just ignore what they don't need : WalkDog(int a, int, int) { ... }
.
Now I have to define functions like WalkDog()
, SingDog()
, DanceDog()
, and then WalkGiraffe()
and SingGiraffe()
(but our giraffes don't dance, so they get some default function that maybe I have to name at least).
My goal is simplicity of maintenance. I'd like to write some template functions like
template<typename AnimalT>
void WalkAnimal(int a) { ... }
so that the table can just be a mapping of the string to the type. (Sometimes I can write such a general function, sometimes I need to write a specialised one, but at least I'm getting the compiler to maintain my table.) But I'm not convinced that C++ (14 in my case, though this could be an argument to upgrade to 17) supports such a thing.
The reason this starts with a string is because of an API accessible on a network. Other clients can't be expected to talk the same C++ types as my system, so they tell me something like {action: "walk", animal: "dog"}
. (It's a protobuf, not JSON, but this question is text.)
// What I want to say, in my dreams:
actions[action_string][animal_string](arg1, arg2, arg3);
though the precise operators aren't important, just an illustration here.
Any suggestions, other than writing the entire table explicitly?
Upvotes: 4
Views: 249
Reputation: 218278
As I understand, you want to replace:
struct AnimalFunction {
void (*Walk)(int a);
void (*Sing)(int a, int b);
void (*Dance)(int a, int b, int c);
};
void WalkDog(int a) {/*..*/}
void SingDog(int a, int b) {/*..*/}
void DanceDog(int a, int b, int c) {/*..*/}
void WalkGiraffe(int a) {/*..*/}
void SingGiraffe(int a, int b) {/*..*/}
std::map<std::string, AnimalFunction> animalFunctions = {
{"Dog", {&WalkDog, &SingDog, &DanceDog}},
{"Giraffe", {&WalkGiraffe, &SingGiraffe, nullptr}},
};
by something like:
struct AnimalFunction {
void (*Walk)(int a);
void (*Sing)(int a, int b);
void (*Dance)(int a, int b, int c);
};
struct Dog {/*..*/};
struct Giraffe {/*..*/};
template <typename T> void WalkT(int a) {/*..*/}
template <typename T> void SingT(int a, int b) {/*..*/}
template <typename T> void DanceT(int a, int b, int c) {/*..*/}
template <> void DanceT<Giraffe>(int a, int b, int c) {/*Empty*/}
// ...
template <typename T>
AnimalFunction MakeAnimalFunction()
{
return {&WalkT<T>, &SingT<T>, &DanceT<T>};
}
std::map<std::string, AnimalFunction> animalFunctions = {
{"Dog", MakeAnimalFunction<Dog>()},
{"Giraffe", MakeAnimalFunction<Giraffe>()},
};
Upvotes: 6