Карта функции повышения различных типов? - PullRequest
7 голосов
/ 15 марта 2009

Мне было интересно, есть ли способ сделать это в C ++?

void func1(const std::string& s)
{
std::cout << s << std::endl;
}

void func2(int me)
{
std::cout << me << std::endl;
}

int main()
{
std::map<std::string, boost::function< ??? > > a_map;

a_map["func1"] = &func1;
a_map["func1"]("HELLO");

}

Есть ли способ сделать то, что у меня есть выше, используя функцию повышения и карту?

Ответы [ 6 ]

2 голосов
/ 15 марта 2009

То, что вы пытаетесь сделать, звучит немного странно. Как правило, контейнером будет набор абстрактных типов, объектов или функций с одинаковой сигнатурой. В противном случае, как вы узнаете, как вызывать функцию при выполнении итерации контейнера? Мне нравится делать контейнер коллекцией объектов функций с известной сигнатурой, а затем использовать Boost.Bind для хранения замыканий, которые вызывают функцию с дополнительными аргументами.

Например:

typedef boost::function<void, void> Function;
typedef std::map<std::string, Function> Functions;

Functions functions:

void foo()
{
  ...
}

functions["foo"] = foo;

void bar(std::string &s)
{
  ...
}

// binds the value "hello" to the s parameter
functions["bar"] = boost::bind(bar, "hello");
2 голосов
/ 15 марта 2009

Существуют способы хранения функций, проблема в том, что для того, чтобы иметь возможность вызывать функцию с нужным аргументом, вам в любом случае необходимо знать сигнатуру вызова функции, и если у вас есть эта информация, может также использовать отдельные карты или использовать более сложный объект, чем boost :: function.

Если вы готовы выполнить небольшую работу и иметь ограниченное количество подписей, вы можете просто сделать что-то вроде этого:

class MultiFunc
{
protected:
    MultiFunc() {}

public:
    typedef void (*stringFunc)(const std::string&);
    typedef void (*intFunc)(int);

    static MultiFunc *Create(stringFunc function);
    static MultiFunc *Create(intFunc function);

    virtual void operator()(const string &) { throw exception(); }
    virtual void operator()(int) { throw exception(); }
    virtual ~MultiFunc();
};

class MultiFuncString : public MultiFunc
{
private:
    stringFunc Function;
public:
    MultiFuncString(stringFunc function) : Function(function) {}
    virtual void operator()(const string &arg) { Function(arg); }
};

class MultiFuncInt : public MultiFunc
{
private:
    intFunc Function;
public:
    MultiFuncInt(intFunc function) : Function(function) {}
    virtual void operator()(int arg) { Function(arg); }
};

MultiFunc *MultiFunc::Create(MultiFunc::stringFunc function)
{
    return new MultiFuncString(function);
}
MultiFunc *MultiFunc::Create(MultiFunc::intFunc function)
{
    return new MultiFuncInt(function);
}

void func1(const std::string& s)
{
std::cout << s << std::endl;
}
void func2(int me)
{
std::cout << me << std::endl;
}

int main()
{
    map<string, MultiFunc *> a_map;
    a_map["func1"] = MultiFunc::Create(&func1);
    (*a_map["func1"])("Hello");
    a_map["func2"] = MultiFunc::Create(&func2);
    (*a_map["func2"])(3);

    // Remember to delete the MultiFunc object, or use smart pointers.
}

Это выводит:

Hello
3

К сожалению, вы не можете создавать шаблонные виртуальные функции или просто обобщаете все это.

2 голосов
/ 15 марта 2009

Вы, вероятно, не можете использовать std::map, так как это однородный контейнер. Попробуйте что-то вроде boost::variant (они поддерживают шаблон посетителя) или boost::tuple

0 голосов
/ 15 марта 2009

Нет. Ты не можешь Поскольку boost :: function не полиморфна, она ломается там. (Требуется фиксированный набор типов аргументов.)

В расширенном почтовом списке говорилось о работе в этом направлении, поэтому поищите в архивах и посмотрите, есть ли какой-нибудь код, который вы могли бы использовать.

Обходным путем будет использование boost :: function, но тогда вам нужно добавить на карту не ваши реальные функции (т.е. func1 / func2), а диспетчерские функции, которые извлекают тип из any-container и вызывают реальную функцию. (И выдает залог, если это не так, как в любом динамическом языке.)

0 голосов
/ 15 марта 2009

интерфейсы магазина:

struct IStringData
{
    virtual std::string get() const = 0;
    virtual ~IStringData() {}
};

и создайте реализации, одна будет содержать строковое значение, другая реализация будет хранить функтор, возможно, в будущем у вас будут другие реализации.

0 голосов
/ 15 марта 2009

прочитайте эту ссылку ниже. В нем говорится об использовании boost :: bind для хранения указателей на функции в std :: map

http://www.gamedev.net/community/forums/topic.asp?topic_id=526381&whichpage=1&#3411515

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...