Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
559 views
Welcome To Ask or Share your Answers For Others

1 Answer

This has nothing to do with SFINAE or templates or C++11 or ADL.

A member shadows all non-members with the same name, regardless of type. If you have a member named f, you cannot refer to any non-member named f, unless you use a qualified name (e.g. ::f).

Just use ::f(*this, t);.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...