C++ has ADL (Argument Dependent Lookup) by which, as its name describes, the context (namespace) of a function can be implied from the context (namespace) of (any of) the argument(s).
fun(a); // if the type of a is in namespace ns deduce ns::f if available
My question is if the reverse is also possible by some technique? By reverse I mean if the context (namespace) can be deduced from the context of the called function. Some sort of "Function Dependent Lookup" (FDL). Fake code:
ns::fun(a); // deduce ns::a if available
I can't figure out a way of doing that. This limitation is particularly annoying for enum
s used to encode functions options. I would like to know if there is a technique to simulate this feature (C++11 would be ok too). Fake code:
ns::fun(Saturday, Tuesday); // Saturday/Tuesday are enum values in namespace ns;
Especially if there is a workaround for enum
s.
This code illustrates the issue:
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)
}
EDIT: @jrok suggested a workaround based on defining nested namespace. For the enum
case, I get this code. Which still has some noise (there is really no "dependent" lookup at all) but it is an improvement.
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);
}
I am not using enum class
because then Saturday
, Sunday
, etc cannot be brough directly in scope (in fact using longname::days::_
would give me a compile error)
Yes and no. Mostly no.
The bad news is if an enum is outside the current scope, such as
Tuesday
, etc then it can't be passed to a function, even if that function was declared in a namespace where the enum was visible. This is because argument lookup occurs first when you write a function call and the arguments can not be passed togun
and then have name lookup occur. Nothing can change this - however there is good news too.Firstly you seem to need behaviour that maps
ns::foo(arg1, arg2)
->{using namespace ns; ns::foo(arg1, arg2);}
. Function calls and templates can't change this but macros kind of can and I included and example.Also I gave a basic example of argument dependent lookup. You can see that the out-of-scope functions GetMonday and GetTuesday (which return your out-of-scope enum) can be found using this mechanism simply because you included one type from that namespace.
RegisterNamespace::val
adds the hidden namespace to the scope when the compiler is trying to find GetMonday, and GetMonday returns aDays
which allows the compiler to findfoo
.Really you want the compiler to alter the scope by adding additional namespaces when it encounters a function from another namespace. However the compiler has already determined the types of the arguments by then, and actually needs them to work out other possible alternatives to the function.