How to remove the current function from the overload set?
-
14-06-2021 - |
Pregunta
I have a function in my namespace, ns::foo
, whose job is to dispatch an invocation of foo
using argument-dependent lookup:
namespace ns
{
template<typename T>
void foo(T x)
{
// call foo through ADL
foo(x);
}
}
I want clients to be able to call foo
without having to manually instantiate it, i.e.:
bar x;
ns::foo(x);
Not
ns::foo<bar>(x);
The problem of course is that ns::foo
is recursive if there is no better match for foo
than ns::foo
.
I don't wish to give ns::foo
a different name, so is there any way to remove it from the overload set inside itself?
Solución
If the foo
to where you want to dispatch is not in the ns
namespace, then this should work:
namespace helper
{
template<typename T>
void _foo(T x)
{
// call foo through ADL
foo(x);
}
}
namespace ns
{
template<typename T>
void foo(T x)
{
::helper::_foo(x);
}
}
The trick is that the call to foo
from _foo
will not consider ns::foo
, because it is not in an argument-dependent namespace. Unless the type of x
happens to be in ns
of course, but then you have a recursion by definition.
UPDATE: You have to put this code just after the definition of namespace ns
:
namespace ns
{
//your useful stuff here
}
namespace helper { /* template _foo */ }
namespace ns { /* template foo */ }
There is no recursion because the helper::_foo
function cannot call the template foo
because it is still not defined.
Otros consejos
If you define your ADL functions with an extra argument, it gives it a different type signature, so you won't have a conflict. I defined the template in global scope, but it will work in the ns
scope as well.
namespace ns
{
class A {};
class B {};
void foo(A, int) { std::cout << "adl: fooA" << std::endl; }
void foo(B, int) { std::cout << "adl: fooB" << std::endl; }
}
template <typename T>
void foo(T t) {
foo(t, 0);
}
int main()
{
ns::A a;
ns::B b;
foo(a); //calls ns::foo
foo(b); //calls ns::foo
}