Workaround for the inverse of Argument Dependent Lookup?
argument-dependent-lookup, c++, c++11, enums, namespaces
Solution
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 to `gun` 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 a `Days` which allows the compiler to find `foo`.
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.
#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;
}
Problem
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)