У вас есть указатель на элемент данных для двух не связанных классов. Ну, вы не можете найти общий тип, который может содержать оба указателя. Он будет работать только в том случае, если параметр функции является указателем члена данных на член производного, потому что он гарантированно будет содержать член, даже если база содержит его:
struct a { int c; }; struct b : a { }; int main() { int b::*d = &a::c; }
Обновление : Думаю, мне следует написать, почему приведенное выше значение неявно преобразуется из a::*
в b::*
. В конце концов, у нас обычно есть от b*
до a*
! Рассмотрим:
struct a { };
struct b : a { int c; };
struct e : a { };
int main() { int a::*d = &b::c; e e_; (e_.*d) = 10; /* oops! */ }
Если бы вышеприведенное было бы справедливо, вы бы сильно облажались. Выше указано , а не , поскольку преобразование из b::*
в a::*
не является неявным. Как видите, мы присваиваем указатель на b :: c, а затем можем разыменовать его, используя класс, который его вообще не содержит! (e
). Компилятор применяет этот порядок:
int main() { int b::*d = &b::c; e e_; (e_.*d) = 10; /* bug! */ }
Он не может скомпилировать сейчас, потому что e
не является производным от b
, класса, к которому принадлежит указатель на член указателя. Хорошо! Следующее, однако, очень допустимо и, конечно, компилируется (измененные классы a
и b
):
struct a { int c; };
struct b : a { };
struct e : a { };
int main() { int e::*d = &a::c; e e_; (e_.*d) = 10; /* works! */ }
Чтобы это работало в вашем случае, вы должны сделать свою функцию шаблоном:
template<typename Class>
void DoThings (int Class::*arg) { /* do something with arg... */ }
Теперь компилятор автоматически определит правильный класс, которому принадлежит данный указатель на член. Вам придется передать экземпляр вместе с указателем на член, чтобы фактически использовать его:
template<typename Class>
void DoThings (Class & t, int Class::*arg) {
/* do something with arg... */
(t.*arg) = 10;
}
Если вы просто хотите установить какого-то члена, которого вы уже знаете на момент написания DoThings, вам будет достаточно:
template<typename Class>
void DoThings (Class & t) {
t.c = 10;
}