2

我不确定这是否与 sfinae 有任何关系,或者只是与任何模板化函数相关的东西。我正在尝试使用 sfinae 基于相应自由函数的存在来启用/禁用成员函数,而该自由函数又根据另一种类型的成员函数的存在来启用/禁用,所有这些都使用此处描述的方法:

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

但是 gcc 4.7.1 在箭头标记的行上给了我这个:

错误:没有用于调用“S::f(S&, const pass&)”的匹配函数
注意:候选是:
注意:模板 decltype ((f((* this), t), void())) S::f (const T&)
注意:模板参数推导/替换失败:
注意:候选人需要 1 个参数,提供 2 个

这显然意味着f上面的全局不被考虑用于重载解决方案。

为什么会这样,我该怎么做才能做到这一点?

另外为什么上面两行没有错误,f在 decltype 中以类似的方式使用?

更新

正如@nm 所说,成员函数完全隐藏自由函数,即使它们的签名不同,所以这里有一个不会破坏 ADL 的解决方法f(与 @nm 建议的全名限定不同)。f_dispatcher在没人会看到的地方()创建自由函数(detail),并在里面完全限定它的名字S::f。在该函数中调用 freef并让 ADL 从那里开始处理它,如下所示:

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

1 回答 1

7

这与 SFINAE 或模板或 C++11 或 ADL 无关。

无论类型如何,成员都会隐藏所有具有相同名称的非成员。如果你有一个成员 named f,你不能引用任何非成员 named f,除非你使用一个限定名(例如::f)。

只需使用::f(*this, t);.

于 2012-07-27T20:24:21.057 回答