I have atleast 16 functions of the following form.
bool Node::some_walker( Arg* arg1 )
{
if(this == NULL)
return false;
bool shouldReturn = false;
if( this->some_walker_p(arg1, shouldReturn) ) //This line alone varies
return true;
if( shouldReturn ) // true is already returned
return false;
return this->std_walker(arg1);
}
The function some_walker_p is a virtual function and i am not able to templatize it. Is there any solution to avoid this code repetition?
Thanks,
Gokul.
It depends on whether the arguments to the private functions are similar or not. The following solutions are possible, ranging from simple and limited to complex and generic:
Equivalent =< Use member-function-pointer)
Same number, different types => Templatize over each argument)
Different numbers/types of arguments => se boost::bind and function objects)
Thanks for the comments given. At first, I only posted the first solution, but there are (as listed) other situations that need different approaches.
Member-function-pointer:
bool Node::walker_caller(Arg* arg1, bool (Node::*memfn)(Arg*, bool))
{
...
if( (this->*memfn)(arg1, shouldReturn) ) //This line alone varies
return true;
...
}
bool Node::some_walker(Arg* arg1)
{
return walker_caller(arg1, &Node::some_walker_p);
}
bool Node::other_walker(Arg* arg1)
{
return walker_caller(arg1, &Node::other_walker_p);
}
Sidenote: I usually typedef the mem-fn-ptr to make the syntax more bearable.
Templated arguments:
I assume you always have two arguments here, but they can have different types.
If you have a limited amount of args-numbers (say 1 and 2), you can could implement walker_caller twice, one impl for one-arg and one for two-arg, both templated.
template<class A1, class A2)
bool Node::walker_caller(A1 arg1, A2 arg2, bool (Node::*memfn)(A1, A2, bool))
{
...
if( (this->*memfn)(arg1, arg2, shouldReturn) ) //This line alone varies
return true;
...
}
bool Node::some_walker(Arg* arg, OtherArg* other_arg)
{
return walker_caller(arg, other_arg, &Node::some_walker_p);
}
bool Node::other_walker(OtherArg* other_arg, YetAnotherArg* yaa)
{
return walker_caller(other_arg, yaa, &Node::other_walker_p);
}
Function objects:
If your walkers use widely different number and argument types, you probably want to use boost::bind, and maybe boost::function. (Use of the latter is not required but cuts down on the generated code size...)
// faster code, as the function object may be inlined, but
// each call instantiates a different walker_caller, so exe might be bigger
template<class F>
bool Node::walker_caller(const F& fn)
{
...
if( fn(shouldReturn) ) //This line alone varies
return true;
...
}
// only one implementation, so smaller foot print but
// all arguments need to be copied into a function objet
// which may be a perf hit if the arguments are big
// (this version is good to have when you inherit from Node...)
bool Node::walker_caller(const boost::function<bool (bool)>& fn)
{
...
if( fn(shouldReturn) ) //This line alone varies
return true;
...
}
bool Node::some_walker(Arg* arg1)
{
return walker_caller(boost::bind(&Node::some_walker_p, this, arg1, _1));
}
bool Node::other_walker(Arg* arg1, OtherArg* arg2)
{
return walker_caller(boost::bind(&Node::some_walker_p, this, arg1, arg2, _1));
}
You can use a (non-virtual) template function which calls a virtual (non-template) function to mimic a templated virtual function. That could help, depending on the structure of your code.
Use a macro.
I know that get a bad rep, but they have legitimate uses. In general, I think it's more acceptable to use them in your implementation code than in your interface code, so I would consider one here.
#define WALKER_MAYBE_DELEGATE( function_name, attempt, fallback, ArgType) \
void Node::function_name(ArgType arg) {\
...
Related
I have a class Frobnicator that handles various requests.
class Frobnicator
{
public:
// Handlers are member functions.
// They optionally take some input. They optionally return some output. But they always take the context!
// There are more types than just int involved, but it's always just one input or void, and one output or void.
void performSomething(Context* context) { /* ... */ } // Takes void, returns void
void setSomething (Context* context, int input) { /* ... */ } // Takes int , returns void
int getSomething (Context* context) { /* ... */ } // Takes void, returns int
int convertSomething(Context* context, int input) { /* ... */ } // Takes int , returns int
template<typename TResult, typename TParameter>
void registerHandler(std::string identifier, TResult(Frobnicator::* handler)(Context*, TParameter))
{
// The external API actually wants a callback that takes and returns JSON. We give it a lambda that does the conversion and calls the actual member function.
// The identifier tells the external API which callback to call for which request. It's not relevant for this question, just to show the idea. Think of something like a REST API.
someExternalApiThatWantsJson.registerHandler(identifier, [&](Context* context, Json input)
{
// Idealy, this would be a one-liner.
//return Json::convertFrom((this->*handler)(context, input.convertTo<TParameter>()));
// But calling Json.convertTo<void>() and Json::convertFrom(void) does not work automagically anyways, so we need to split it up manually:
Json result;
if constexpr (std::is_same<TResult, void>::value)
if constexpr (std::is_same<TParameter, void>::value) (this->*handler)(context ) ; // Takes void, returns void
else (this->*handler)(context, input.convertTo<TParameter>()) ; // Takes something, returns void
else
if constexpr (std::is_same<TParameter, void>::value) result = Json::convertFrom((this->*handler)(context )); // Takes void, returns something
else result = Json::convertFrom((this->*handler)(context, input.convertTo<TParameter>())); // Takes something, returns something
return result;
});
}
// Set up the handlers.
void setup()
{
// The problem is that some of these calls don't work:
registerHandler ("PerformSomething", &Frobnicator::performSomething); // "failed template argument deduction"
registerHandler<void, void>("PerformSomething", &Frobnicator::performSomething); // Trying to specify the types explicitly: "substitution failure [with TResult = void, TParameter = void]: argument may not have 'void' type"
registerHandler ("SetSomething" , &Frobnicator::setSomething); // Compiles fine
registerHandler ("GetSomething" , &Frobnicator::getSomething); // "failed template argument deduction"
registerHandler<int , void>("GetSomething" , &Frobnicator::getSomething); // Trying to specify the types explicitly: "substitution failure [with TResult = int, TParameter = void]: argument may not have 'void' type"
registerHandler ("ConvertSomething", &Frobnicator::convertSomething); // Compiles fine
}
};
TResult can be int or void and it works fine. But it only works when TParameter isn't void.
How can I make registerHandler also accept pointers to functions that take no arguments?
The idea is to have the member functions' signatures very clean and the calls to registerHandler mostly clean. So giving performSomething and getSomething a dummy parameter is out of the question. Manually specifying the types when calling registerHandler is ugly but I'll accept it, if it's necessary.
The body of registerHandler is relatively short and mostly deals with distinguishing void from non-void anyways, so providing a specialization for when TParameter is void would be a fine solution:
template<typename TResult>
void registerHandler<TResult, void>(std::string identifier, TResult(Frobnicator::* handler)(Context*))
Except that "function template partial specialization is not allowed".
Use template parameter pack to deal with void / non-void cases, since the number of arguments is indetermined (1 or 2).
template<typename TResult, typename... TParameter>
void registerHandler(std::string identifier, TResult(Frobnicator::* handler)(Context*, TParameter...))
The second parameter accepts a pointer to member function whose the first argument is required to be Context*, that's it.
Then,
void setup()
{
registerHandler ("PerformSomething", &Frobnicator::performSomething);
registerHandler ("SetSomething" , &Frobnicator::setSomething);
registerHandler ("GetSomething" , &Frobnicator::getSomething);
registerHandler ("ConvertSomething", &Frobnicator::convertSomething);
}
The implementation of registerHandler may also need some changes, the std::is_same_v<TParameter, void> can be replaced by sizeof...(TParameter) == 0.
Demo
Well. Sometimes you waste an hour because you narrowly miss a solution. Just don't make it a specification:
template<typename TResult>
void registerHandler(std::string identifier, TResult(Frobnicator::* handler)(Context*))
But!: This is a valid solution for me, but it would be nice to have a solution that does not require duplicating almost the entire function body. So better answers are absolutely welcome!
What I would do is follow the 0 1 infinity rule and write infinity instead of 2 cases.
Support any number of arguments. Map to tuples. Empty tuples for 0, mono for 1, etc.
Then the conversion code should work naturally. You can bind the call to be (take tuple, return tuple), then write the input/output code to handle 0, 1, or n from/to json.
Now the json function call logic no longer cares about void. The packing unpacking does. And the code that calls the raw function from tuples and packs it into a tuple return does.
template<class F>
auto packresult(F&&f){
if constexpr(f() is void)
f()
return tuple<>{};
else if constexpr(f returns a tuple)
return f();
else
return std::make_tuple(f());
}
Now you do the same for inputs
auto unpackargs(auto&&f){
return [f](auto&&tup){
return std::apply(f, tup);
}
}
which makes your code look like:
converttupletojson(packresult(bind(unpackargs(bind this to method), getargsfromjson<Args...>())))
and viola, the most surprising musical instrument.
The Goal:
decide during runtime which templated function to use and then use it later without needing the type information.
A Partial Solution:
for functions where the parameter itself is not templated we can do:
int (*func_ptr)(void*) = &my_templated_func<type_a,type_b>;
this line of code can be modified for use in an if statement with different types for type_a and type_b thus giving us a templated function whose types are determined during runtime:
int (*func_ptr)(void*) = NULL;
if (/* case 1*/)
func_ptr = &my_templated_func<int, float>;
else
func_ptr = &my_templated_func<float, float>;
The Remaining Problem:
How do I do this when the parameter is a templated pointer?
for example, this is something along the lines of what I would like to do:
int (*func_ptr)(templated_struct<type_a,type_b>*); // This won't work cause I don't know type_a or type_b yet
if (/* case 1 */) {
func_ptr = &my_templated_func<int,float>;
arg = calloc(sizeof(templated_struct<int,float>, 1);
}
else {
func_ptr = &my_templated_func<float,float>;
arg = calloc(sizeof(templated_struct<float,float>, 1);
}
func_ptr(arg);
except I would like type_a, and type_b to be determined during runtime. I see to parts to the problem.
What is the function pointers type?
How do I call this function?
I think I have the answer for (2): simply cast the parameter to void* and the template function should do an implicit cast using the function definition (lease correct me if this won't work as I think it will).
(1) is where I am getting stuck since the function pointer must include the parameter types. This is different from the partial solution because for the function pointer definition we were able to "ignore" the template aspect of the function since all we really need is the address of the function.
Alternatively there might be a much better way to accomplish my goal and if so I am all ears.
Thanks to the answer by #Jeffrey I was able to come up with this short example of what I am trying to accomplish:
template <typename A, typename B>
struct args_st {
A argA;
B argB;
}
template<typename A, typename B>
void f(struct args_st<A,B> *args) {}
template<typename A, typename B>
void g(struct args_st<A,B> *args) {}
int someFunction() {
void *args;
// someType needs to know that an args_st struct is going to be passed
// in but doesn't need to know the type of A or B those are compiled
// into the function and with this code, A and B are guaranteed to match
// between the function and argument.
someType func_ptr;
if (/* some runtime condition */) {
args = calloc(sizeof(struct args_st<int,float>), 1);
f((struct args_st<int,float> *) args); // this works
func_ptr = &g<int,float>; // func_ptr should know that it takes an argument of struct args_st<int,float>
}
else {
args = calloc(sizeof(struct args_st<float,float>), 1);
f((struct args_st<float,float> *) args); // this also works
func_ptr = &g<float,float>; // func_ptr should know that it takes an argument of struct args_st<float,float>
}
/* other code that does stuff with args */
// note that I could do another if statement here to decide which
// version of g to use (like I did for f) I am just trying to figure out
// a way to avoid that because the if statement could have a lot of
// different cases similarly I would like to be able to just write one
// line of code that calls f because that could eliminate many lines of
// (sort of) duplicate code
func_ptr(args);
return 0; // Arbitrary value
}
Can't you use a std::function, and use lambdas to capture everything you need? It doesn't appear that your functions take parameters, so this would work.
ie
std::function<void()> callIt;
if(/*case 1*/)
{
callIt = [](){ myTemplatedFunction<int, int>(); }
}
else
{
callIt = []() {myTemplatedFunction<float, float>(); }
}
callIt();
If I understand correctly, What you want to do boils down to:
template<typename T>
void f(T)
{
}
int somewhere()
{
someType func_ptr;
int arg = 0;
if (/* something known at runtime */)
{
func_ptr = &f<float>;
}
else
{
func_ptr = &f<int>;
}
func_ptr(arg);
}
You cannot do that in C++. C++ is statically typed, the template types are all resolved at compile time. If a construct allowed you to do this, the compiler could not know which templates must be instanciated with which types.
The alternatives are:
inheritance for runtime polymorphism
C-style void* everywhere if you want to deal yourself with the underlying types
Edit:
Reading the edited question:
func_ptr should know that it takes an argument of struct args_st<float,float>
func_ptr should know that it takes an argument of struct args_st<int,float>
Those are incompatible. The way this is done in C++ is by typing func_ptr accordingly to the types it takes. It cannot be both/all/any.
If there existed a type for func_ptr so that it could take arguments of arbitrary types, then you could pass it around between functions and compilation units and your language would suddenly not be statically typed. You'd end up with Python ;-p
Maybe you want something like this:
#include <iostream>
template <typename T>
void foo(const T& t) {
std::cout << "foo";
}
template <typename T>
void bar(const T& t) {
std::cout << "bar";
}
template <typename T>
using f_ptr = void (*)(const T&);
int main() {
f_ptr<int> a = &bar<int>;
f_ptr<double> b = &foo<double>;
a(1);
b(4.2);
}
Functions taking different parameters are of different type, hence you cannot have a f_ptr<int> point to bar<double>. Otherwise, functions you get from instantiating a function template can be stored in function pointers just like other functions, eg you can have a f_ptr<int> holding either &foo<int> or &bar<int>.
Disclaimer: I have already provided an answer that directly addresses the question. In this answer, I would like to side-step the question and render it moot.
As a rule of thumb, the following code structure is an inferior design in most procedural languages (not just C++).
if ( conditionA ) {
// Do task 1A
}
else {
// Do task 1B
}
// Do common tasks
if ( conditionA ) {
// Do task 2A
}
else {
// Do task 2B
}
You seem to have recognized the drawbacks in this design, as you are trying to eliminate the need for a second if-else in someFunction(). However, your solution is not as clean as it could be.
It is usually better (for code readability and maintainability) to move the common tasks to a separate function, rather than trying to do everything in one function. This gives a code structure more like the following, where the common tasks have been moved to the function foo().
if ( conditionA ) {
// Do task 1A
foo( /* arguments might be needed */ );
// Do task 2A
}
else {
// Do task 1B
foo( /* arguments might be needed */ );
// Do task 2B
}
As a demonstration of the utility of this rule of thumb, let's apply it to someFunction(). ... and eliminate the need for dynamic memory allocation ... and a bit of cleanup ... unfortunately, addressing that nasty void* is out-of-scope ... I'll leave it up to the reader to evaluate the end result. The one feature I will point out is that there is no longer a reason to consider storing a "generic templated function pointer", rendering the asked question moot.
// Ideally, the parameter's type would not be `void*`.
// I leave that for a future refinement.
void foo(void * args) {
/* other code that does stuff with args */
}
int someFunction(bool condition) {
if (/* some runtime condition */) {
args_st<int,float> args;
foo(&args);
f(&args); // Next step: pass by reference instead of passing a pointer
}
else {
args_st<float,float> args;
foo(&args);
f(&args); // Next step: pass by reference instead of passing a pointer
}
return 0;
}
Your choice of manual memory management and over-use of the keyword struct suggests you come from a C background and have not yet really converted to C++ programming. As a result, there are many areas for improvement, and you might find that your current approach should be tossed. However, that is a future step. There is a learning process involved, and incremental improvements to your current code is one way to get there.
First, I'd like to get rid of the C-style memory management. Most of the time, using calloc in C++ code is wrong. Let's replace the raw pointer with a smart pointer. A shared_ptr looks like it will help the process along.
// Instead of a raw pointer to void, use a smart pointer to void.
std::shared_ptr<void> args;
// Use C++ memory management, not calloc.
args = std::make_shared<args_st<int,float>>();
// or
args = std::make_shared<args_st<float,float>>();
This is still not great, as it still uses a pointer to void, which is rarely needed in C++ code unless interfacing with a library written in C. It is, though, an improvement. One side effect of using a pointer to void is the need for casts to get back to the original type. This should be avoided. I can address this in your code by defining correctly-typed variables inside the if statement. The args variable will still be used to hold your pointer once the correctly-typed variables go out of scope.
More improvements along this vein can come later.
The key improvement I would make is to use the functional std::function instead of a function pointer. A std::function is a generalization of a function pointer, able to do more albeit with more overhead. The overhead is warranted here in the interest of robust code.
An advantage of std::function is that the parameter to g() does not need to be known by the code that invokes the std::function. The old style of doing this was std::bind, but lambdas provide a more readable approach. Not only do you not have to worry about the type of args when it comes time to call your function, you don't even need to worry about args.
int someFunction() {
// Use a smart pointer so you do not have to worry about releasing the memory.
std::shared_ptr<void> args;
// Use a functional as a more convenient alternative to a function pointer.
// Note the lack of parameters (nothing inside the parentheses).
std::function<void()> func;
if ( /* some runtime condition */ ) {
// Start with a pointer to something other than void.
auto real_args = std::make_shared<args_st<int,float>>();
// An immediate function call:
f(real_args.get());
// Choosing a function to be called later:
// Note that this captures a pointer to the data, not a copy of the data.
// Hence changes to the data will be reflected when this is invoked.
func = [real_args]() { g(real_args.get()); };
// It's only here, as real_args is about to go out of scope, where
// we lose the type information.
args = real_args;
}
else {
// Similar to the above, so I'll reduce the commentary.
auto real_args = std::make_shared<args_st<float,float>>();
func = [real_args]() { g(real_args.get()); };
args = real_args;
}
/* other code that does stuff with args */
/* This code is probably poor C++ style, but that can be addressed later. */
// Invoke the function.
func();
return 0;
}
Your next step probably should be to do some reading on these features so you understand what this code does. Then you should be in a better position to leverage the power of C++.
The sd-bus requires one to callback functions when defining d-bus methods. As i am doing C++14, i would like to have those calls to a class object on_msg_method_here() functions. What i am trying to achieve is something like this (in pseudo c++):
int callback_dbus_method_foo( message* msg, void* userdata, ... )
{
MyClass* cls = (MyClass*)userdata;
Type0 var0;
if ( message_process( msg, signature[0], &var0 ) != 0 )
//.. error here
Type1 var1;
if ( message_process( msg, signature[1], &var1 ) != 0 )
//.. error here
//... and these continue from 0 to N
TypeN varN;
if ( message_process( msg, signature[N], &varN ) != 0 )
//.. error here
int dbus_ret = cls->on_msg_method_foo( var1, var2, ..., varN )
handle_dbus_ret( msg, dbus_ret // ... );
return 0;
}
int MyClass::register_callbacks( ... )
{
// Well really we have something really different, this is to demonstrate
// pass 'this' as userdata* to callback function
dbus_register_callback( "method_foo",
&callback_dbus_method_foo, this )
}
Now i know i can do this with C-macros, but how to do this properly with C++14 varidic macros?
As far as i understand, the trouble of calling certain class object certain method can be handled with std::bind (and pass that via userdata pointer), and the variable declaration and message_process can be done with variadic template peeling, but how to get those declared variables (var0, var1, .. on the pseudo code example) expanded properly to the call? In short, how to do this magic:
MyClass::register_callbacks()
{
Mystic fun_to_call = std::bind( &MyClass::on_dbus_method_foo, this );
dbus_register_callback( "method_foo",
super_magic_template<int,double,bool>, &fun_to_call );
}
There are a couple things I would do in order to get an elegant and generic solution.
We need a way to gather variables (var0, var1, ..., varN) and pass them to a function. For that, I would first have a wrapper that queries such variables given it's index i. I'm not sure what signature is in your exemple, but I'm sure you can work around this.
template <class T>
T get_var(message* msg, unsigned i) {
T var;
if ( message_process( msg, signature[i], &var ) != 0)
throw std::runtime_error("Oups"); // In this context, it's easier to deal with errors with exception.
return var;
}
We can then gather all variables by unpacking variadic template arguments, along with associated index_sequence used for indexing. Something like
template <class... Vars, class F>
void callback_wrapper(F& fcn, message* msg) {
callback_wrapper_impl(fcn, msg, std::make_index_sequence<sizeof...(Vars)>());
}
template <class... Vars, class F, size_t... i>
void callback_wrapper_impl(F& fcn, message* msg, std::index_sequence<i...>) {
fcn(get_var<Vars>(msg, i)...);
}
Another difficulty arises with using std::bind, which returns the function-like object fun_to_call. We can't pass that to dbus_register_callback as a function pointer, which does not carry any data, neither can we pass a pointer to it as userdata, because fun_to_call is a local variable, hence it's lifetime is too short.
Instead of relying only on a super_magic_template callback, I would do a wrapper around dbus_register_callback that offers a simpler interface, let's call it modern_dbus_register_callback. The most straightforward solution I see is to use dynamic storage duration at the cost of memory allocation and an extra level of indirection - this is similar to type erasure used in std::function. Note that you can optimize this if sizeof(fun_to_call) < sizeof(void*), by passing fun_to_call by value as userdata - this is small value optimization. I believe using lambdas with no capture can be useful, as they are convertibles to function pointers and avoid lots of template boilerplate. Some extra work might be required to handle errors while avoiding memory leaks.
template <class... Vars, class F>
void modern_dbus_register_callback(const char* name, F& fcn) {
std::unique_ptr<F> fcn_ptr = std::make_unique<F>(fcn);
dbus_register_callback(name, [](message* msg, void* userdata){
std::unique_ptr<F> fcn_ptr(static_cast<F*>(userdata));
callback_wrapper<Vars...>(*fcn_ptr, msg);
}, fcn_ptr.release());
}
This can then be used as
modern_dbus_register_callback<int,double,bool>("method_foo", fun_to_call);
I have a templated function similar to:
template<class T>
T foo( string sReturnType )
{
//pseudo code
if( sReturnType = "string" )
{
lookup data in string table
return a string
}
else
{
look up in number table
return number answer
}
}
usage would be something like: foo("string")
inside the function, there needs to be logic that either pulls from a string table or a number table and returns that value. I played around with this and wasn't able to get it to work as I expected. It seems like it should be pretty straight forward and easy to do. Is this a valid approach and use of templates? I looked at template specialization but then you end up writing two separate code bases anyways, why not use an overloaded function? Is there a better way?
No - there is no way to declare a function having different return types (A template function may have different return types, but these would depend on a template parameter).
You could return a type encapsulating all possible return types (like boost::any or boost::variant) instead.
You have to overload foo(); There's pretty much no way around it.
std::string foo( std::string )
{
// look up data...
return std::string();
}
int foo( int )
{
// look up data...
return -1;
}
int i = foo( 1 );
std::string s = foo( "string" );
I think the problem is pretty common. You have some input string, and have to call a function depending on the content of the string. Something like a switch() for strings.
Think of command line options.
Currently I am using:
using std::string;
void Myclass::dispatch(string cmd, string args) {
if (cmd == "foo")
cmd_foo(args);
else if (cmd == "bar")
cmd_bar(args);
else if ...
...
else
cmd_default(args);
}
void Myclass::cmd_foo(string args) {
...
}
void Myclass::cmd_bar(string args) {
...
}
and in the header
class Myclass {
void cmd_bar(string args);
void cmd_foo(string args);
}
So every foo and bar I have to repeat four (4!) times. I know I can feed the function pointers and strings to an static array before and do the dispatching in a loop, saving some if...else lines. But is there some macro trickery (or preprocessor abuse, depending on the POV), which makes is possible to somehow define the function and at the same time have it update the array automagically?
So I would have to write it only twice, or possibly once if used inline?
I am looking for a solution in C or C++.
It sounds like you're looking for the Command pattern
Something like this:
Create a map like this
std::map<std::string, Command*> myMap;
then just use your key to execute the command like this....
std::map<std::string, Command*>::iterator it = myMap.find(str);
if( it != myMap.end() ) {
it->second->execute()
}
To register your commands you just do this
myMap["foo"] = new CommandFoo("someArgument");
myMap["bar"] = new CommandBar("anotherArgument");
The basic solution, per my link in the question comment, is to map a string to a function call of some sort.
To actually register the string -> function pointer/functor pair:
Firstly, have a singleton (shock! horror!) dispatcher object.
Let's call it TheDispatcher - it's a wrapper for a map<string,Func>, where
Func is your function pointer or functor type.
Then, have a register class:
struct Register {
Register( comst string & s, Func f ) {
TheDispatcher.Add( s, f );
}
};
Now in your individual compilation units you create
static objects (shock! horror!):
Register r1_( "hello", DoSayHello );
These objects will be created (assuming the code is not in a static library) and will automatically register with TheDispatcher.
And at run-time, you look up strings in TheDispatcher and execute the associated function/functor.
as alternative to the Command pattern you can build an hashtable of string -> function pointers:
typedef void (*cmd)(string);
The ugly macro solution, which you kind-of asked for. Note that it doesn't automatically register, but it does keep some things synchronized, and also will cause compile errors if you only add to mappings, and not the function in the source file.
Mappings.h:
// Note: no fileguard
// The first is the text string of the command,
// the second is the function to be called,
// the third is the description.
UGLY_SUCKER( "foo", cmd_foo, "Utilize foo." );
UGLY_SUCKER( "bar", cmd_bar, "Turn on bar." );
Parser.h:
class Myclass {
...
protected:
// The command functions
#define UGLY_SUCKER( a, b, c ) void b( args )
#include Mappings.h
#undef UGLY_SUCKER
};
Parser.cpp:
void Myclass::dispatch(string cmd, string args) {
if (cmd == "")
// handle empty case
#define UGLY_SUCKER( a, b, c ) else if (cmd == a) b( args )
#include Mappings.h
#undef UGLY_SUCKER
else
cmd_default(args);
}
void Myclass::printOptions() {
#define UGLY_SUCKER( a, b, c ) std::cout << a << \t << c << std::endl
#include Mappings.h
#undef UGLY_SUCKER
}
void Myclass::cmd_foo(string args) {
...
}
You'll have to at least define the functions and add them to some registry. (If they are to be non-inline member functions of some class, you'll also have to declare them.) Other than some domain-specific language generating the actual code (like cjhuitt's macro hackery), I see no way around mentioning these functions two (or three) times.