Por que funções herdadas múltiplas com o mesmo nome, mas assinaturas diferentes, não são tratadas como funções sobrecarregadas?

O fragment a seguir produz um erro “chamada ambíguo para foo” durante a compilation e gostaria de saber se há alguma maneira de contornar esse problema sem qualificar totalmente a chamada para foo:

#include  struct Base1{ void foo(int){ } }; struct Base2{ void foo(float){ } }; struct Derived : public Base1, public Base2{ }; int main(){ Derived d; d.foo(5); std::cin.get(); return 0; } 

Então, a questão é como o título diz. Idéias? Quer dizer, os seguintes trabalhos são perfeitos:

 #include  struct Base{ void foo(int){ } }; struct Derived : public Base{ void foo(float){ } }; int main(){ Derived d; d.foo(5); std::cin.get(); return 0; } 

    As regras de pesquisa de membros são definidas na Seção 10.2 / 2

    As etapas a seguir definem o resultado da pesquisa de nomes em um escopo de class, C Primeiro, toda declaração para o nome na class e em cada um de seus subobjects de class base é considerada. Um nome de membro f em um subobject B esconde um nome de membro f em um sub-object A se A é um subobject de class base de B Quaisquer declarações que são tão ocultas são eliminadas da consideração . Cada uma dessas declarações que foi introduzida por uma declaração de uso é considerada como sendo de cada subobject de C que é do tipo que contém a declaração designada pela declaração de utilização. Se o conjunto resultante de declarações não for todo de sub-objects do mesmo tipo, ou o conjunto tiver um membro não estático e include membros de subobjects distintos, haverá uma ambigüidade e o programa será mal formado . Caso contrário, esse conjunto é o resultado da pesquisa.

     class A { public: int f(int); }; class B { public: int f(); }; class C : public A, public B {}; int main() { C c; cf(); // ambiguous } 

    Então você pode usar as declarações A::f e B::f para resolver essa ambigüidade

     class C : public A, public B { using A::f; using B::f; }; int main() { C c; cf(); // fine } 

    O segundo código funciona sem falhas porque void foo(float) está dentro do escopo de C. Na verdade d.foo(5); chama void foo(float) e não a versão int .

    A pesquisa de nome é uma fase separada para sobrecarregar a resolução .

    A pesquisa de nome ocorre primeiro. Esse é o processo de decidir em qual escopo o nome se aplica. Neste caso, devemos decidir se d.foo significa dD::foo , ou d.B1::foo , ou d.B2::foo . As regras de pesquisa de nome não levam em conta parâmetros de function ou nada; é puramente sobre nomes e escopos.

    Somente depois que essa decisão é tomada, executamos a resolução de sobrecarga nas diferentes sobrecargas da function no escopo onde o nome foi encontrado.

    Em seu exemplo, chamar d.foo() encontraria D::foo() se houvesse tal function. Mas não há nenhum. Então, trabalhando para trás nos escopos, ele tenta as classs base. Agora foo poderia igualmente procurar B1::foo ou B2::foo por isso é ambíguo.

    Pela mesma razão, você teria ambiguidade chamando foo(5); não qualificado foo(5); dentro de uma function de membro D


    O efeito da solução recomendada:

     struct Derived : public Base1, public Base2{ using Base1::foo; using Base2::foo; 

    é que isso cria o nome D::foo e faz com que ele identifique duas funções. O resultado é que d.foo resolve para dD::foo , e então a resolução de sobrecarga pode acontecer nessas duas funções que são identificadas por D::foo .

    Nota: Neste exemplo, D::foo(int) e Base1::foo(int) são dois identificadores para a function one; mas, em geral, para o processo de pesquisa de nomes e resolução de sobrecargas, não faz diferença se elas são duas funções separadas ou não.

    Será que vai trabalhar para você?

     struct Derived : public Base1, public Base2{ using Base2::foo;}