The use-case
I'm trying to build a small interpreter for a text-based command console. E.g., say there's a function somewhere:
void SetBrightness(float brightness) { /* ... */ }
Then it should be possible to write in the console "SetBrightness 0.5"
, which should result in the above function being called. We can register a command at runtime:
void AddCommand(const std::string& command, CommandInterpreterCallback* callback);
This function should bind not only a callback function, but also a list of strongly typed parameters matching to what the callback expects, to the string command
. I define a class to hold the callback:
using ParamType = std::variant<int32_t, float, std::string, bool>;
class CommandInterpreterCallback
{
public:
void SetParameters(const std::vector<ParamType>& args)
{
mNumParameters = args.size();
if (mNumParameters >= 1) { mArg1 = args[0]; }
// ...
}
void SetFunction(std::function<void> callback)
{
mCallback = callback; // TODO: How to solve this?
}
private:
uint8_t mNumParameters = 0;
ParamType mArg1 = ParamType<bool>; // possibly an array instead here
std::function<void> mCallback; // TODO: How to solve this?
};
The challenge
I really wish for the parameter passing to be strongly-typed, e.g. the function SetBrightness()
must have a floating-point number. So if the user writes "SetBrightness true"
, the function should not get called. Also, I do not want to specify the function parameter as an std::variant<...>
, because it looks messy and makes calling the function from other parts of the code more difficult.
But I'm not sure how I can declare the mCallback
member inside the class, because it should somehow be parametric. I understand that I can set the type to e.g. std::function<void(float)>
. But then, what if I want to bind another function which accepts a boolean?
Maybe I could use std::variant
as well to specify the type of mCallback
, but that sounds like an exponential complexity solution.
Is there a good way around these limitations? I hope I describe the problem well enough.
You might start with something like:
Demo