Сейчас я смотрю какой-то код, который был портирован и не может скомпилироваться. Код был написан в стиле «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
и в идеале хотел бы сводить изменения к минимуму.