4

There is some class which have methods like:

int getSomething1();
std::string getSomething2();
someClass getSomething3();

There is structure which describes fields of this class like:

{"name of field", pointer to getter, std::type_info}

Then I would like to use it as follows:

if(type == int){
   field_int = (int)getter();
}
else if(type == std::string){
   field_string = (std::string)getter();
}
etc.

How to transform getters like

 int getSomething1();
 std::string getSomething2();
 etc.

to some universal function pointer and then to get the correct value of field?

iammilind
  • 68,093
  • 33
  • 169
  • 336
scdmb
  • 15,091
  • 21
  • 85
  • 128

5 Answers5

3

This answer of mine to another question addresses your problem pretty well. With some minor modifications, you get this:

template<class C, class T>
T get_attribute(const C& instance, T (C::*func)() const) {
    return (instance.*func)();
}

Assuming the following:

struct Foo {
    int getSomething1() const;
    std::string getSomething2() const;
    someClass getSomething3() const;
};

You can use it like this:

Foo foo;
int value = get_attribute<Foo, int>(foo, &Foo::getSomething1);
std::string value = get_attribute<Foo, std::string>(foo,  &Foo::getSomething2);
someClass value = get_attribute<Foo, someClass>(foo,  &Foo::getSomething3);

You can of course transform get_attribute to a functor to bind some or all of the arguments.

Community
  • 1
  • 1
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • I think it's a little bit more complicated than that - from the question, the OP is holding a secondary structure where these "pointer_to_something"s should be stored.. – Nim Oct 10 '11 at 09:24
  • @Nim: Yeah, I just got that. I have modified it accordingly, and it should work fine. – Björn Pollex Oct 10 '11 at 09:26
  • 2
    @Nim The real problem here is that he wants to select the function dynamically. Whether the function itself is a template or not doesn't really change anything in this regard. (As written, the template looks like extra verbiage; it doesn't seem to do anything concrete except increase the number of lines of code.) – James Kanze Oct 10 '11 at 09:27
1

What you are trying to achieve can be better achieved with already existing containers such as a boost fusion sequence. I'd advice that you try this first.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
Nim
  • 33,299
  • 2
  • 62
  • 101
  • @Bjorn, thx - I normally just use the latest release - but that link is better... – Nim Oct 10 '11 at 09:33
1

There is no formal universal function pointer, the equivalent of void* for data. The usual solution is to use void (*)(); you are guaranteed that you can convert any (non-member) function pointer to this (or any other function pointer type) and back without loss of information.

If there is a certain similarity in the function signatures (e.g. all are getters, with no arguments) and how they are used, it may be possible to handle this with an abstract base class and a set of derived classes (possibly templated); putting pointers to instances of these classes in a map would definitely be more elegant than an enormous switch.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
0

Templates to the rescue!

// Create mapping of type to specific function
template <typename T> T getSomething(); // No default implementation
template <> int getSomething<int>() { return getSomething1(); } 
template <> std::string getSomething<std::string>() { return getSomething2(); }
template <> someClass getSomething<someClass>() { return getSomething3(); }
// Convenience wrapper
template <typename T> void getSomething(T& t) { t = getSomething<T>(); }
// Use
int i = getSomething<int>();
std::string s;
getSomething(s);
MSalters
  • 173,980
  • 10
  • 155
  • 350
  • What does the template buy us here (except extra lines of code)? (I can see using the template if you want to wrap the call in some sort of class. But I'd need to know more about his actual use to be able to say what might be appropriate in such a case.) – James Kanze Oct 10 '11 at 09:29
0

As I understand, your difficulty is in storing the function pointers, since they are of different types. You can solve this using Boost.Any and Boost.Function.

#include <boost/any.hpp>
#include <boost/function.hpp>

int getInt() {
    return 0;  
}

std::string getString() {
    return "hello";
}

int main()
{
    boost::function<boost::any ()> intFunc(getInt);
    boost::function<boost::any ()> strFunc(getString);

    int i = boost::any_cast<int>(intFunc());
    std::string str = boost::any_cast<std::string>(strFunc());
}
Paul Manta
  • 30,618
  • 31
  • 128
  • 208