开发者

Universal function pointer

开发者 https://www.devze.com 2023-04-12 11:15 出处:网络
There is some class whi开发者_运维知识库ch have methods like: int getSomething1(); std::string getSomething2();

There is some class whi开发者_运维知识库ch 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?


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.


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.


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.


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);


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());
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号