Tipo de ponteiro para membro da classe base

Eu tenho um problema em relação aos ponteiros de membros. O código a seguir falha ao compilar usando o CC do Oracle Solaris Studio 12.2 e o cygwin GCC 4.3.4, mas funciona com o Microsoft Visual C ++ 2010:

struct A {
  int x;
};

struct B : public A {
};

template<typename T> class Bar {
public:
  template<typename M> void foo(M T::*p);
};

int main(int, char *[]) {
    Bar<B> bbar;
    bbar.foo(&B::x);
    return 0;
}

Na penúltima linha, os dois compiladores mencionados acima não conseguem encontrar uma correspondência paraBar<B>::foo(int A::*). Eu escrevi um teste simples para confirmar que o tipo da expressão&B::x é na verdadeint A::*:

// ...

static void foo(int A::*p) {
  std::cout << "A" << std::endl;
}

static void foo(int B::*p) {
  std::cout << "B" << std::endl;
}

int main(int, char *[]) {
    foo(&B::x);  // prints "A", even on MS VC++ 2010 
    return 0;
}

A seguinte solução alternativa funciona com o GCC (ainda não testado com o Oracle CC), mas falha com o VC ++ devido à ambiguidade:

template<typename T> class Bar {
public:
  template<typename M> void foo(M T::*p);
  template<typename M, typename _T_base> inline void foo(M _T_base::*p) {
      foo(static_cast<M T::*>(p));
  }
};

Minha pergunta: qual comportamento está correto? Aparentemente, o VC ++ faz um upcast implícito deint A::* paraint B::* para satisfazer a chamada para o modelo de função de membro, os outros dois compiladores não deveriam considerar fazer o mesmo?

questionAnswers(1)

yourAnswerToTheQuestion