I'm not sure if this has anything to do with sfinae, or just something thats relevant for any templated function. I am attempting to use sfinae to enable/disable a member function based on existence of corresponding free function, which in turn is enabled/disabled based on existance of member function in another type, all using method described here:
struct S;
template <typename T>
inline auto f(S& s, T const& t)
-> decltype(t.f(s), void())
{
t.f(s);
}
struct S
{
template <typename T>
auto f(T const& t)
-> decltype(f(*this, t), void())
{
f(*this, t); // <------------------------------------------- HERE
}
};
struct pass
{
void f(S&) const
{
//...
}
};
struct fail
{
};
int main()
{
S s;
s.f(pass()); // should compile fine
//s.f(fail()); // should fail to compile due to absence of f from S
return 0;
}
however gcc 4.7.1 gives me this on the line marked by arrow:
error: no matching function for call to 'S::f(S&, const pass&)'
note: candidate is:
note: template decltype ((f((* this), t), void())) S::f(const T&)
note: template argument deduction/substitution failed:
note: candidate expects 1 argument, 2 provided
which apparently means that global f
above is not considered for overload resolution.
Why is that and what do I do to make it do so?
Also why are there no errors two lines above that, where f
used in decltype in similar fashion?
UPDATE
As @n.m. said, member functions completely shadow free functions, even when their signatures are different, so here is a workaround that doesn't break ADL for f
(unlike the full name qualification suggested by @n.m. ). Make free function (f_dispatcher
) somewhere nobody will look (detail
), and fully qualify its name inside S::f
. In that function call free f
and let ADL take care of it from there onwards, like so:
struct S;
template <typename T>
inline auto f(S& s, T const& t)
-> decltype(t.f(s), void())
{
t.f(s);
}
namespace detail
{
template <typename T>
inline auto f_dispatcher(S& s, T const& t)
-> decltype(f(s, t), void())
{
f(s, t);
}
}
struct S
{
template <typename T>
auto f(T const& t)
-> decltype(detail::f_dispatcher(*this, t), void())
{
detail::f_dispatcher(*this, t);
}
};
struct pass
{
void f(S&) const
{
//...
}
};
struct fail
{
};
int main()
{
S s;
s.f(pass()); // compiles fine
//s.f(fail()); // fails to compile due to absence of f from S
return 0;
}
See Question&Answers more detail:os