La búsqueda de nombres y la resolución de sobrecarga son diferentes. El nombre debe encontrarse primero en un ámbito, es decir, debemos encontrar uno X
para que do_stuff
se resuelva el nombre X::do_stuff
, independientemente del uso del nombre, y luego seleccione la resolución de sobrecarga entre las diferentes declaraciones de X::do_stuff
.
El proceso NO es identificar todos esos casos A::do_stuff
, B::do_stuff
etc. que son visibles, y luego realizar una resolución de sobrecarga entre la unión de eso. En cambio, se debe identificar un solo alcance para el nombre.
En este código:
struct Baz : public Foo, public Bar
{
void func ()
{
do_stuff (1.1f); // ERROR HERE
}
};
Baz
no contiene el nombre do_stuff
, por lo que se pueden buscar las clases base. Pero el nombre aparece en dos bases diferentes, por lo que la búsqueda de nombres no puede identificar un alcance. Nunca llegamos tan lejos como la resolución de sobrecarga.
La solución sugerida en la otra respuesta funciona porque introduce el nombre do_stuff
al alcance de Baz
, y también introduce 2 sobrecargas para el nombre. Por lo tanto, la búsqueda de nombres determina ese do_stuff
medio Baz::do_stuff
y luego selecciona la resolución de sobrecarga de las dos funciones que se conocen como Baz::do_stuff
.
Por otro lado, el sombreado es otra consecuencia de la búsqueda de nombres (no es una regla en sí misma). La búsqueda de nombre selecciona el alcance interno, por lo que cualquier cosa en el alcance externo no coincide.
Otro factor de complicación ocurre cuando la búsqueda dependiente de argumentos está en juego. Para resumir muy brevemente, la búsqueda de nombres se realiza varias veces para una llamada de función con argumentos de tipo de clase: la versión básica como se describe en mi respuesta, y luego nuevamente para cada tipo de argumento. Luego, la unión de los ámbitos encontrados entra en el conjunto de sobrecarga. Pero eso no se aplica a su ejemplo ya que su función solo tiene parámetros de tipo incorporado.