станд.:: карта указателей функции членства?

Я должен реализовать std::map с <std::string, fn_ptr> пары. Указатели функции являются указателями на методы того же класса, который владеет картой. Идея состоит в том, чтобы иметь прямой доступ к методам вместо того, чтобы реализовать переключатель или эквивалент.

(Я использую std::string как ключи для карты)

Я довольно плохо знаком с C++, таким образом, кто-либо мог отправить некоторый псевдокод или ссылку, которая говорит о реализации карты с указателями функции? (указатели на методы, принадлежавшие тому же классу, который владеет картой),

Если Вы думаете, что существует лучший подход к моей проблеме, предложения также приветствуются.

19
задан skypjack 23 September 2016 в 21:46
поделиться

3 ответа

Это самое простое, что я могу придумать. Обратите внимание на отсутствие проверки ошибок, и карту, вероятно, можно было бы сделать статической.

#include <map>
#include <iostream>
#include <string>
using namespace std;

struct A {
    typedef int (A::*MFP)(int);
    std::map <string, MFP> fmap;

    int f( int x ) { return x + 1; }
    int g( int x ) { return x + 2; }


    A() {
        fmap.insert( std::make_pair( "f", &A::f ));
        fmap.insert( std::make_pair( "g", &A::g ));
    }

    int Call( const string & s, int x ) {
        MFP fp = fmap[s];
        return (this->*fp)(x);
    }
};

int main() {
    A a;
    cout << a.Call( "f", 0 ) << endl;
    cout << a.Call( "g", 0 ) << endl;
}
32
ответ дан 30 November 2019 в 03:29
поделиться

Реализация шаблона может выглядеть так:

class Factory {
public:
    enum which {
        foo, bar, baz
    };

    template<which w>
    A* newA(...);
    ...
};
template<Factory::which w>
A* Factory::newA(...) {
    /* default implementation */
    throw invalid_argument();
}
template<>
A* Factory::newA<Factory::foo>(...) {
    /* specialization for a 'foo' style A */
    ...
}
....

Это требует, чтобы значение, используемое для определения того, какой newA вызывается, было известно во время компиляции. Вы можете потенциально использовать const char * ​​в качестве параметра шаблона, но это не гарантирует, что он будет работать на всех компиляторах.

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

Кроме того, если вы используете enum , а не строку для типа ключа, вам не нужно беспокоиться о том, чтобы проверить, существует ли ключ на карте. Хотя кто-то может передать неверный ключ enum в newA , ему придется явно привести аргумент, что означает, что они не собираются делать это случайно. Мне сложно представить случай, когда кто-то намеренно вызывает сбой в newA ; потенциальные сценарии связаны с безопасностью, но программист приложения может вывести приложение из строя без использования вашего класса.

m трудно представить себе случай, когда кто-то намеренно вызовет сбой в newA ; потенциальные сценарии связаны с безопасностью, но программист приложения может вывести приложение из строя без использования вашего класса.

m трудно представить себе случай, когда кто-то намеренно вызовет сбой в newA ; потенциальные сценарии связаны с безопасностью, но программист приложения может вывести приложение из строя без использования вашего класса.

3
ответ дан 30 November 2019 в 03:29
поделиться

Другой вариант - использовать делегаты вместо указателей на функции. Эта реализация делегата довольно быстра, поддерживает полиморфизмы и хорошо работает с контейнерами stl. У вас может быть что-то вроде:

class MyClass {
public:
    // defines
    typedef fastdelegate::FastDelegate2<int, int, int> MyDelegate;
    typedef std::map<std::string, MyDelegate> MyMap;

    // populate your map of delegates
    MyClass() {
        _myMap["plus"] = fastdelegate::MakeDelegate(this, &Plus);
        _myMap["minus"] = fastdelegate::MakeDelegate(this, &Minus);
    }

    bool Do(const std::string& operation, int a, int b, int& res){
        MyMap::const_iterator it = _myMap.find(operation);
        if (it != _myMap.end()){
            res = it.second(a,b);
            return true;
        }

        return false; 
    }
private:
    int Plus (int a, int b) { return a+b; }
    int Minus(int a, int b) { return a-b; }
    MyMap _myMap;    
};      
1
ответ дан 30 November 2019 в 03:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: