I have the following class:
template<int P>
struct A {
struct B {
auto abs() const { return 1; }
};
};
Specifically A
is supposed to be the finite field of integers modulo P, and B
is the class representing elements from this finite field. Then I have a generic implementation of the extended GCD algorithm which is supposed to use the abs
function. The problem I want the extended GCD algorithm implementation to work on basic types (int, long, etc), as well as A<P>::B
. So I need to implement a non-member abs
that will call A<P>::B::abs
. I tried a three techniques, two of them don't work and one that works but is not suitable.
Technique 1 (doesn't work): use argument-dependent lookup (ADL). Define the following inside the body of A
but outside the body of B
:
auto abs(B const &e) { return e.abs(); }
It won't work since ADL looks only inside namespaces not class scopes. UPDATE : ADL doesn't work here because abs
is an instance method. However as per T.C.'s answer, if you make it a friend function it works correctly and ADL finds it!
Technique 2 (doesn't work): use constrained function template in global or namespace scope:
template<int P>
auto abs(typename A<P>::B const &e) { return e.abs(); }
This will also not work because P
is in a non-deduced context.
Technique 3 (works, but not satisfactory): use unconstrained function template in global or namespace scope:
template<typename T>
auto abs(T const &e) { return e.abs(); }
This works. However, it is unconstrained. I would like to restrict instantiations of this function template only to A<P>
(for P
unknown beforehand), and other class templates (for polynomial rings and field extensions). The problem is I am not sure how to use SFINAE if P
is in a non-deduced context.
template<int P>
struct A {
struct B {
auto abs() const { return 1; }
};
friend auto abs(B const &e) { return e.abs(); }
// ^^^^^^
};
Then let ADL work its magic.
(Defining it inside B
is also fine. The choice's up to you.)