I have a class with a member called f
and simultaneously a generic free function called f
.
The free function f
is meant to called from another member (called g
below).
class A{};
int f(A const& a){return 5;} // generic free f
template<class T>
struct B{
void f() const{} // member f
int g(){
T a;
auto i = f(a) + 1; // here (cannot resolve f)
return i;
}
};
int main(){
B<A> b;
int j = b.g();
assert(j == 6);
}
It turns out that my compilers (GCC and clang) can't resolve the call to f
.
error: no matching function for call to ‘B::f(A&)’
auto i = f(a) + 1; ^
note: candidate: void B::f() const
void f() const{} ^
note: candidate expects 0 arguments, 1 provided
This is of course because it gets confused with the member f
.
Yet, only ::f
makes sense.
If I were to force the member function, I could say this->f
or B::f
.
However I know no syntax that can do the opposite, i.e. force the free function ::f
or actually some external resolution to f
given by ADL and disable the member function (something like notthis->f
).
I could use using ::f
:
... int g(){
T a;
using ::f;
auto i = f(a) + 1;
return i;
} ...
But, this wouldn't be generic because I don't know to which namespace T
belongs and I want generic code. (here it is ::
but for T = A
, but for other classes in other namespaces I don't know).
For example, the class B<ns::C>
should compile for:
namespace ns{
class C{};
int f(C const& a){return 5;} // genetic free f
}
Of course I could rename everything to avoid the clash but that is not an acceptable solution, suppose that it makes sense to have both the free and the member function called f
.
Is this a bug on GCC and clang, a defect on the language or am I missing some obvious way to specify to not use the member function?
(the example uses C++11 but the question is valid for any version of C++).
Thanks to @JohnZwinck, this is the current workaround
class A{};
int f(A const& a){return 5;} // genetic free f
class nonmember{
protected:
template<class TT> static decltype(auto) _f(TT&& t){return f(std::forward<TT>(t));}
};
template<class T>
struct B : private nonmember{
void f() const{} // member f
int g(){
T a;
auto i = _f(a) + 1;
return i;
}
};