C++11 style SFINAE and function visibility on template instantiation

拜拜、爱过 提交于 2019-11-28 09:52:57

问题


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;
}

回答1:


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);.



来源:https://stackoverflow.com/questions/11694970/c11-style-sfinae-and-function-visibility-on-template-instantiation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!