c++ - ADL falla(¿o no se hace?) Para la función con parámetro de plantilla adicional(no deducido)
c++11 templates (1)
Debido a que una llamada de función a una plantilla de función con argumentos de plantilla explícitamente especificados requiere que el nombre de la plantilla se encuentre mediante búsqueda ordinaria; hasta que esa ADL no pueda entrar .
Del estándar: $ 17.8.1 / 8 Especificación explícita del argumento de la plantilla [temp.arg.explicit]
(énfasis mío)
[Nota: Para los nombres de funciones simples, la búsqueda dependiente del argumento 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 a función ([basic.lookup.unqual]). Pero cuando se utiliza 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 hay ningún nombre visible, la llamada no está sintácticamente bien formada y no se aplica la búsqueda dependiente de los argumentos. Si algún nombre es visible, se aplica la búsqueda dependiente del argumento y se pueden encontrar plantillas de funciones adicionales en otros espacios de nombres. [Ejemplo:
namespace A { struct B { }; template<int X> void f(B); } namespace C { template<class T> void f(T t); } void g(A::B b) { f<3>(b); // ill-formed: not a function call A::f<3>(b); // well-formed C::f<3>(b); // ill-formed; argument dependent lookup applies only to unqualified names using C::f; f<3>(b); // well-formed because C::f is visible; then A::f is found by argument dependent lookup }
- fin del ejemplo] - nota final]
La última oración ofrece una posible solución; puede agregar la declaración de la plantilla de función en cualquier lugar para hacer que el nombre sea visible para ser llamado. p.ej
template<typename>
void notfound();
int main() {
N::C object;
std::cout
<< found(object) << std::endl
<< notfound<bool>(object) << std::endl
<< notfound<bool, N::C&>(object) << std::endl; // btw the 2nd template argument should be N::C&
}
namespace N {
class C {};
template<typename X>
char const * found(X && x) {
return "found";
}
template<typename, typename X>
char const * notfound(X && x) {
return "not found";
}
}
Esto define un espacio de nombres N
con una clase C
y dos plantillas de funciones. found
tiene un único parámetro de plantilla, que se puede deducir del argumento de la función. notfound
tiene un parámetro de plantilla adicional que no se puede deducir.
Dado el siguiente código de prueba ( en ideone ):
#include <iostream>
int main() {
N::C object;
std::cout
<< found(object) << std::endl
<< notfound<bool>(object) << std::endl // ERROR
<< notfound<bool, N::C>(object) << std::endl; // ERROR
}
Supuse que la búsqueda dependiente del argumento encontraría tanto encontrado como no found
través del espacio de nombre adjunto más interno (que es N
) del tipo de argumento N::C
Sin embargo:
prog.cpp: In function ‘int main()’:
prog.cpp:21:6: error: ‘notfound’ was not declared in this scope
<< notfound<bool>(object) << std::endl
^~~~~~~~
prog.cpp:21:6: note: suggested alternative:
prog.cpp:12:15: note: ‘N::notfound’
char const * notfound(X && x) {
^~~~~~~~
(el mismo error para notfound<bool, N::C>(object)
después de comentar la notfound<bool>(object)
)
¿Por qué no se encuentra encontrado a través de ADL?
Antecedentes: estoy implementando una función get
para algunas clases contenedoras, todo relativamente similar a std::get(std::tuple)
. La clase contenedora, que es un detalle de implementación, vive en algunos espacios de nombres lib::aspect::part::impl
. No quiero que los usuarios de la biblioteca especifiquen using lib::aspect::part::impl::get
por razones obvias.