There are different approaches to this particular problem. You can use inheritance, by which you create a base Command
and then implement some execute
function (you can also implement help
, validate
....). Then create a dispatcher function that associates the names with the actual implementations of the commands (in a lookup table of sorts, possibly a map
).
While this does not solve your issue with locality, that issue might or not be real. That is, the implementation of the commands might be all over the place, but there is a single place that determines what commands are available in the CLI.
If locality is such an important thing for you (at the cost of not having a single place in your source code where all commands in use are listed), you can provide a registration mechanism that is globally accessible, then provide a helper type that during construction will register the function into the mechanism. You can then create one such object with each function definition.
CommandRegistry& getCommandRegistry(); // Access the registry
struct CommandRegister {
CommandRegister(const char* name, Function f) {
getCommandRegistry().registerCmd(name,f);
}
// Optionally add deregistration
};
// ...
void Func2() {...}
static CommandRegister Func2Registration("function2",&Func2);
I personally prefer to go the other way... having a single place in the code where all commands are listed, as it allows for a single location in which to find the command (text) to code that executes it. That is, when you have a few commands and someone else needs to maintain one of them, it makes it easier to go from the command line to the actual code that executes it.