c++ - Resolución de sobrecarga buscando espacios de nombres.
overload-resolution (2)
ADL no se usa cuando están involucrados argumentos de plantilla explícitos a menos que introduzca una declaración de función de plantilla en el punto de llamada. Está utilizando una forma no calificada de get
utilizando un argumento de plantilla no tipo 0
, por lo que necesita introducir una declaración de función de plantilla o usar la versión calificada de get
como std::get<0>(ar)
.
En standardese [temp.arg.explicit]/8
: (énfasis mío)
[Nota: para nombres de funciones simples, la búsqueda dependiente de argumentos (6.4.2) se aplica incluso cuando el nombre de la función no es visible dentro del alcance de la llamada. Esto se debe a que la llamada todavía tiene la forma sintáctica de una llamada de función (6.4.1). Pero cuando se usa una plantilla de función con argumentos de plantilla explícitos, la llamada no tiene la forma sintáctica correcta a menos que haya una plantilla de función con ese nombre visible en el punto de la llamada. Si no se ve tal nombre, la llamada no está sintácticamente bien formada y no se aplica la búsqueda dependiente del argumento . Si algún nombre de este tipo es visible, se aplica una búsqueda dependiente del argumento y se pueden encontrar plantillas de funciones adicionales en otros espacios de nombres.
EDITAR:
Como @Yakk - Adam Nevraumont ha señalado en el comentario, sin la presencia de la declaración de la función de plantilla, la expresión get<0>(ar)
se analizará como (get<0)>(ar)
, es decir, como una serie de expresiones de comparación en lugar de una llamada de función.
El siguiente código falla como se esperaba, porque no se encuentra una sobrecarga de get
. Usar std::get
resolvería el problema.
#include <array>
int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//fails, get was not declared in this scope
}
Sin embargo, la introducción de una versión con plantillas de get
, aunque no coincida con la llamada a la función, de alguna manera hace que el compilador use la versión std::get
:
#include <array>
template <typename T>
void get(){};
int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//returns 2
}
No puedo encontrar ninguna parte de la norma que explica esto. ¿Es esto un error en los 3 compiladores que probé (probablemente no), o me falta algo?
Este comportamiento fue probado en
- MSVC 15.9.2
- Clang 8.0.0
- GCC 9.0.0 (todavía una versión experimental)
EDITAR: Estoy al tanto de ADL. Pero si ADL hace que el segundo código funcione, ¿por qué no en la primera parte?
Tenga en cuenta que esto cambió en C ++ 20 como resultado de P0846R0 . Un nombre no calificado seguido de un <
token para el cual la búsqueda ordinaria no calificada encuentra una o más funciones o encuentra que no se asume que ahora se denomina una plantilla y <
se analiza en consecuencia.