Неявный тип неизвестен при передаче указателя на функцию - PullRequest
3 голосов
/ 08 июня 2011

Сейчас я смотрю какой-то код, который был портирован и не может скомпилироваться. Код был написан в стиле «C» и передает указатели функций для установки определенных мутаторов на объект. Заполняемый объект объявляется следующим образом:

class Person
{
    std::string n_;
    int a_;

    public:
        void name( const std::string& n ) { n_ = n; }
        std::string name() const { return n_; }
        void age( const int& a ) { a_ = a; }
        int age() const { return a_; }
};

Довольно стандартные вещи. Тогда у нас есть несколько интересных функций, которые я сократил для краткости:

typedef void (Person::FnSetStr)(const std::string& s);
typedef void (Person::FnSetInt)(const int& i);

void setMem( const std::string& label, Person* person, FnSetStr fn)
{
    // Do some stuff to identify a std::string within a message from the label.
    // assume that 'val_s' contains the string value of the tag denoted by
    // the label.
    (person->*fn)(val_s);
}

void setMem( const std::string& label, Person* person, FnSetInt fn)
{
    // Do some stuff to identify an int within a message from the label.
    // assume that 'val_i' contains the int value of the tag denoted by the
    // label.
    (person->*fn)(val_i);
}

И тогда это называется следующим образом:

Person* person = new Person;
setMem("Name", person, Person::name );   // (1)
setMem("Age", person, Person::age );     // (2)

Идея состоит в том, чтобы передать метку, объект и адрес соответствующего мутатора. Тип 3-го параметра используется, чтобы заставить компилятор выбрать, какую перегрузку вызывать, и конкретная перегрузка затем получает подходящую переменную, готовую и вызывает функцию, передающую ее в качестве параметра для установки значения объекта.

Это работало на старом компиляторе Solaris. Однако, когда он компилируется в GCC, я получаю сбои в точках (1) и (2):

error: no matching function for call to
    'setMem( const std::string& label, Person* person, <unknown type> )'

Похоже, новый компилятор обрабатывает, скажем, Person::age как тип, а не указатель на функцию и не может разрешить перегрузку. Я смотрю на изменение кода, чтобы использовать функциональный объект, а не прямые указатели на функции.

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

1 Ответ

5 голосов
/ 08 июня 2011

Сначала измените объявление:

typedef void (Person::*FnSetStr)(const std::string& s);
typedef void (Person::*FnSetInt)(const int& i);

Затем смените звонок:

setMem("Name", person, &Person::name );   // (1)
setMem("Age", person, &Person::age );     // (2)

Создает чистоту на уровне предупреждения 4 в VS 2010.

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