views:

286

answers:

9

I'm trying to have method void run( string method ) which would run method in that class. For example:

class Foo {
    public:
    void run( string method ) {
        // this method calls method *method* from this class
    }
    void bar() {
        printf( "Function bar\n" );
    }
    void foo2() {
        printf( "Function foo2\n" );
    }
}

Foo foo;

int main( void ) {
    foo.run( "bar" );
    foo.run( "foo2" );
}

this would print:

Function bar
Function foo2

Thanks! :)

+15  A: 

You can create an std::map which maps strings to member function pointers, as long as all the functions you want to call have the same signature.

The map would be declared like:

 std::map<std::string, void(Foo::*)()> function_map;
Charles Salvia
otherwise, `if(){}else if(){}else if(){} else{}` is still here ;-)
Michael Krelin - hacker
if I were to go for this solution, though, I'd make it a static map - never postpone till runtime what you can do at compile time.
Michael Krelin - hacker
+2  A: 

You can make a map of member function pointers, with the key of the map being the name of the function. Pointers to member functions are a little hard to work with though.

http://www.parashift.com/c++-faq-lite/pointers-to-members.html

The easier way is to do a bunch of if-then-else blocks in your run function to call the appropriate function.

Mark Ransom
+6  A: 

The map solution already mentioned would work for fixed lists of functions, but I don't think there is a way to introspect like this in general in C++. That is, you can't have a function void perform( string methodName ) that says "do I have a method called methodName? If so, call it."

Asher Dunn
Yes, C++ is not at all like Java in this regard.
Omnifarious
...also not like Objective-C, Python, Perl, JavaScript, Ruby, C#...
benzado
@benzado: Objective-C is completely different you are sending a message. If the object knows how to react to the message it will execute code. Python/Perl/Javascript: all objects are just maps so methods are just objects attached as the value. C# and Java are different in that type introspection is allowed (AKA reflection) thus allowing you to find the methods by name and then call them.
Martin York
@benzado: Cont. Using maps as the bases of all objects makes type safety a nightmare. Java/C# reflection is fantastic for the development tool builders (and some libraries). But using refelction in real applications leads to brittle code.
Martin York
@MartinYork: If you're saying that Objective-C doesn't offer runtime introspection, you're wrong (see `class_copyMethodList()` and friends). If you're trying to pick a strong vs. weak type system fight, I'm not interested. Otherwise, I'm not sure what point you're trying to make.
benzado
@benzado, I despise Java, but for good or ill, it's what they teach in school these days and so what I figured the original poster was most familiar with.
Omnifarious
@benzado: I never said Objective-C did not have introspection, but nor do you need to use it to call methods by name as Objective-C does run-time binding of messages at the object. Not trying to pick a fight just expanding with more detail on your pithy remarks.
Martin York
+2  A: 

As the other posters have said, you need to do this by hand in C++, as the language doesn't have inbuilt Reflection.

Languages like C# and Java have this built in so it may be worth rethinking your choice of language, depending on what you're needing this for.

Groky
A: 

You can't do it without RTTI or some kind of map. Or a solution like this:

class Foo {
    public:
    void run( string method ) {
        bar(method);
        foo2(method);
     // ... more methods here
    }
    void bar(string method) {
        if (method != "bar") return;
        printf( "Function bar\n" );
    }
    void foo2(string method) {
        if (method != "foo2") return;
        printf( "Function foo2\n" );
    }
}

Foo foo;

int main( void ) {
    foo.run( 'bar' );
    foo.run( 'foo2' );
}

this will give you the same result you wanted

alemjerus
Your suggested solution is simply awful. It's inefficient, because for n methods every call to `run` will result in n method calls no matter what. It's also unmaintainable, because the logic for mapping a name to a method is distributed among the methods.
benzado
+8  A: 

As others have pointed out, C++ doesn't do this kind of reflection out of the box (and odds are that it's probably not what you want to be doing.)

But I'll mention that there do exist some preprocessors out there which implement this functionality for a subset of class types and methods. Qt's moc is an example of this, and it's part of the signal/slot mechanics. Notice method() and methodCount() on the QMetaObject ...

The way Qt does this is by injecting a tool into your build process that makes tables and compiles them in with the rest of your code. It's all stuff you could have written by hand--not a language feature.

Hostile Fork
+4  A: 

Although the previous answers are for your solution, your solution doesn't look like the correct one for your problem.

I have two suggestions: 1) Build a better abstract base class or 2) Use a base class for functors (function objects). Let's look at them in more detail...

Given a project of simulating a processor's instruction set, we can simulate the execution with:

struct Instruction_Interface
{
  virtual void execute(void) = 0;
};

typedef std::vector<Instruction_Interface *> Instruction_Container;

//...
Instruction_Container::iterator iter;
Instruction_Container program_instructions;
//...
for (iter =  program_instructions.begin();
     iter != program_instructions.end();
     ++iter)
{
  (*iter)->execute(); // Execute the instruction;
}

This allows calling of each instruction's execute method, regardless of the kind of instruction. One can add more methods to the interface; in this example one could add "toString" which would convert the instruction to text.

Idea 2:  Functors

Establish a base class or interface for the functions you want to use. Place them into a container and iterate over the container. The iteration can be conditional also:

struct Functor_Interface
{
   virtual std::string  get_name(void) const = 0;
   virtual void         execute(void) = 0;
   virtual void         execute_if_name(const std::string& name)
   { if (name == get_name())
     {
        execute();
     }
   }
};

typedef std::vector<Functor_Interface *> Functor_Container;
//...
Functor_Container the_functors;
//...
Functor_Container::iterator iter;
for (iter =  the_functors.begin();
     iter != the_functors.end();
     ++iter)
{
   (*iter)->execute_if_name("loader"); // Execute the functor if it is a *loader*.
   (*iter)->execute_if_name("math");
}

In summary, think over your design to see if there is a better process that doesn't require function names, but instead lets either the function decide to execute or generically executes blind methods.

Thomas Matthews
A: 

For straight C++, the above answer is good. However, some toolkits (eg, Qt) can add introspection to C++. This is perhaps a heavier change and not what you want for an existing project, but if you're starting a project that might need introspection its worth searching for toolkits / wrappers that add it.

Sarah
A: 

Just to mention there exist some reflection libraries like CAMP: http://dev.tegesoft.com/projects/camp/apidoc/index.html

Nikko