Указатель универсальной функции - PullRequest
4 голосов
/ 10 октября 2011

Есть некоторый класс, который имеет методы, такие как:

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

Есть структура, которая описывает поля этого класса, такие как:

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

Тогда я хотел бы использовать его следующим образом:

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

Как преобразовать геттеры, такие как

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

, в некоторый указатель универсальной функции, а затем получить правильное значение поля?

Ответы [ 5 ]

3 голосов
/ 10 октября 2011

Этот мой ответ на другой вопрос решает вашу проблему довольно хорошо. С некоторыми незначительными изменениями вы получите это:

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

Предполагая следующее:

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

Вы можете использовать это так:

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

Конечно, вы можете преобразовать get_attribute в функтор, чтобы связать некоторые или все аргументы.

1 голос
/ 10 октября 2011

Нет формального универсального указателя на функцию, эквивалентную void* для данных.Обычное решение - использовать void (*)();вам гарантировано, что вы можете преобразовать любой (не являющийся членом) указатель функции в этот (или любой другой тип указателя функции) и обратно без потери информации.

Если имеется некоторое сходство в сигнатурах функций (напримервсе являются получателями, без аргументов) и как они используются, может быть возможно обработать это с помощью абстрактного базового класса и набора производных классов (возможно, шаблонных);размещение указателей на экземпляры этих классов на карте определенно будет более элегантным, чем огромный переход.

1 голос
/ 10 октября 2011

То, чего вы пытаетесь достичь, может быть лучше достигнуто с уже существующими контейнерами, такими как последовательность boost fusion . Я бы посоветовал вам сначала попробовать это.

0 голосов
/ 10 октября 2011

Как я понимаю, ваша сложность заключается в хранении указателей функций, поскольку они бывают разных типов. Вы можете решить эту проблему, используя Boost.Any и 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 голосов
/ 10 октября 2011

Шаблоны на помощь!

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