Передача указателя метода в качестве параметра шаблона: почему я не могу использовать здесь унаследованный метод? - PullRequest
3 голосов
/ 04 февраля 2012

Следующий код (сжатый из более крупной программы) не компилируется с clang или gcc.

struct S1 {
  void m1() {}
};

template<typename B> struct S2 : B {
  void m2() {}
  void m3();
};

template<typename S, void (S::*m)()> void f1(S* o) {
  (o->*m)();
}

template<typename B> void S2<B>::m3() {
  f1<S2, &S2::m1>(this);
}

int main() {
  void (S2<S1>::*m)() = &S2<S1>::m1;
  S2<S1> o;
  o.m3();
}

Вот сообщение об ошибке clang:

bad.cc:15:3: error: no matching function for call to 'f1'
  f1<S2, &S2::m1>(this);
  ^~~~~~~~~~~~~~~
bad.cc:21:5: note: in instantiation of member function 'S2<S1>::m3' requested
      here
  o.m3();
    ^
bad.cc:10:43: note: candidate template ignored: invalid explicitly-specified
      argument for template parameter 'm'
template<typename S, void (S::*m)()> void f1(S* o) {
                                          ^
1 error generated.

Этот код компилируется, когда язаменить m1 на m2.Очевидно, что компилятор знает о m1 (другое сообщение, когда я заменяю m1 на m4), так почему указатель на него должен быть недопустимым в этом контексте?

1 Ответ

3 голосов
/ 04 февраля 2012

Дело в том, что тип m1 void(S1::*)(void), а не void(S2::*)(void).Так что исправьте это, используя известное имя базового класса:

struct S1 {
    void m1() {}
};

template<typename B> struct S2 : B {
    void m2() {}
    void m3();
};

template<typename S, typename B, void (B::*m)(void)> void f1(S* o) {
    (o->*m)();
}

template<typename B> void S2<B>::m3() {
    f1<S2, B, &B::m1>(this);
}

int main() {
    S2<S1> o;
    o.m3();
}

Конечно, это (пока) не масштабируется до методов, определенных в косвенных базовых классах, но с небольшим количеством TMP это можно сделать (будет)посмотрим, смогу ли я опубликовать это, пока длится перерыв Going Native 2012:))

Более «гибкий» подход будет выглядеть так:S2<B>& можно преобразовать в B&, если макет класса уже явно не гарантирует этого, как в вашем текущем примере.

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