c++ - resueltos - ¿Solución para el inverso de Argument Dependent Lookup?
inverso multiplicativo ejemplos resueltos (1)
Si y no. Mayormente no
La mala noticia es que si una enumeración está fuera del alcance actual, como el Tuesday
, etc., entonces no se puede pasar a una función, incluso si esa función se declaró en un espacio de nombres donde la enumeración estaba visible. Esto se debe a que la búsqueda de argumentos se produce primero cuando se escribe una llamada de función y los argumentos no se pueden pasar a la gun
y luego se produce la búsqueda de nombre. Nada puede cambiar esto, sin embargo, también hay buenas noticias.
En primer lugar, parece que necesita un comportamiento que mapee ns::foo(arg1, arg2)
-> {using namespace ns; ns::foo(arg1, arg2);}
{using namespace ns; ns::foo(arg1, arg2);}
. Las llamadas a funciones y las plantillas no pueden cambiar esto, pero las macros tipo de can y yo incluimos y ejemplo.
También di un ejemplo básico de búsqueda dependiente de argumentos. Puede ver que las funciones fuera del alcance GetMonday y GetTuesday (que devuelven la enumeración fuera del alcance) se pueden encontrar utilizando este mecanismo simplemente porque incluyó un tipo de ese espacio de nombres. RegisterNamespace::val
agrega el espacio de nombres oculto al ámbito cuando el compilador intenta encontrar GetMonday, y GetMonday devuelve un Days
que permite al compilador encontrar foo
.
Realmente desea que el compilador modifique el alcance agregando espacios de nombres adicionales cuando encuentra una función de otro espacio de nombres. Sin embargo, el compilador ya ha determinado los tipos de argumentos para entonces, y realmente los necesita para encontrar otras alternativas posibles a la función.
#include <iostream>
namespace hidden {
enum RegisterNamespace { val };
enum Days {
Monday,
Tuesday
};
void foo(Days a , Days b){std::cout << "Called foo/n";}
Days GetMonday(RegisterNamespace a = val){return Days::Monday;}
Days GetTuesday(RegisterNamespace b = val){return Days::Tuesday;}
}
using namespace std;
#define UseNamespace(ns, x) do {using namespace ns; x;} while (0)
int main()
{
//with a macro
UseNamespace(hidden,hidden::foo(Monday, Tuesday));
{
//foo is found by argument dependent lookup
using hidden::Days;
foo(Days::Monday,Days::Tuesday);
}
{
using r = hidden::RegisterNamespace;
//foo and GetMonday / GetTuesday are all found by argument dependent lookup
foo(GetMonday(r::val),GetTuesday(r::val));
}
return 0;
}
C ++ tiene ADL (Argument Dependent Lookup) mediante el cual, como su nombre lo describe, el contexto (espacio de nombres) de una función puede ser implícito desde el contexto (espacio de nombres) de (cualquiera de) los argumentos.
fun(a); // if the type of a is in namespace ns deduce ns::f if available
Mi pregunta es si lo contrario también es posible por alguna técnica? Por reversa quiero decir si el contexto (espacio de nombres) se puede deducir del contexto de la función llamada. Algún tipo de "Búsqueda dependiente de funciones" (FDL). Código falso:
ns::fun(a); // deduce ns::a if available
No puedo encontrar una manera de hacerlo. Esta limitación es particularmente molesta para las enum
utilizadas para codificar las opciones de funciones. Me gustaría saber si existe una técnica para simular esta característica (C ++ 11 también estaría bien). Código falso:
ns::fun(Saturday, Tuesday); // Saturday/Tuesday are enum values in namespace ns;
Especialmente si hay una solución para enum
s.
Este código ilustra el problema:
namespace longname{
class A{};
void fun(A const& a){}
A global_a;
enum Days { Saturday,Sunday,Tuesday,Wednesday,Thursday,Friday};
void gun(Days d1, Days d2){}
}
int main(){
longname::A a;
fun(a); // cool, longname::fun(a) not necessary, fun is deduced from context
longname::fun(global_a); // error, not cool, global_a context not deduced,
// must use then longname::fun(longname::global_a)
longname::gun(Saturday, Tuesday); // error, particularly not cool, the Saturday is not deduced from context
// must use then longname::gun(longname::Saturday, longname::Tuesday)
// or at best gun(longname::Saturday, longname::Tuesday)
}
EDITAR: @jrok sugirió una solución basada en la definición de espacio de nombres anidados. Para el caso enum
, obtengo este código. Que todavía tiene algo de ruido (en realidad no hay una búsqueda "dependiente") pero es una mejora.
namespace longname{
namespace days{
enum _ { Saturday,Sunday,Tuesday,Wednesday,Thursday,Friday};
}
void gun(days::_ d1, days::_ d2){}
}
int main(){
using namespace longname::days; // some noise still here
longname::gun(Saturday, Tuesday);
}
No estoy usando la enum class
porque el Saturday
, el Sunday
, etc. no pueden ser directamente en el alcance (de hecho, using longname::days::_
me daría un error de compilación)