enable_if'd继承的成员函数的名称查找错误

Mar*_*rio 7 c++ language-lawyer

我偶然发现了这个奇怪的名称查找问题,其中基类成员函数似乎根本不参与重载选择,即使它是使用using语句导入的.基类和派生类的成员函数都是SFINAE'd enable_if_t.

我能够使用以下代码重现我的问题:https://gcc.godbolt.org/z/ueQ-kY

#include <iostream>
#include <type_traits>

class MyTag {};

struct Base
{
    template <typename RType>
    std::enable_if_t<std::is_convertible<RType, int>::value> create(RType /*&&*/ ref)
    {
        std::cout << "Base::create(RType ref)" << std::endl;
    }
};

struct Derived : Base
{
    using Base::create;

    template <typename Tag>
    std::enable_if_t<std::is_same<Tag, MyTag>::value> create(Tag /*&&*/ tag)
    {
        std::cout << "Derived::create(Tag tag)" << std::endl;
    }
};

int main()
{
    Derived d;

    d.create(MyTag());
    d.create(0); // [x86-64 clang 7.0.0 #1] error: no matching member function for call to 'create'
}
Run Code Online (Sandbox Code Playgroud)

虽然GCC在没有警告的情况下编译上面的代码,但clang,icc和MSVC无法为调用d.create(0);和错误构建找到合适的重载.事实上,从错误消息判断,似乎Base::create甚至没有参与重载决议.

但是,当两个成员函数中的一个将其参数作为转发引用时,代码在所有主要编译器上编译良好.

YSC*_*YSC 5

Gcc错了,应该拒绝你的例子.

using-declaration:
    using using-declarator-list ;
Run Code Online (Sandbox Code Playgroud)

[namespace.udecl]/1

每个使用说明符在一个using声明引入了一组声明到其中所述声明性区域使用声明出现.该组通过引入的声明用声明符通过进行合格名称查找发现([basic.lookup.qual],[class.member.lookup]在用于名称)使用说明符,不包括如下所述隐藏功能.

排除的功能是:

[namespace.udecl]/15

using-declarator将基类的声明带入派生类时,派生类中的成员函数和成员函数模板覆盖和/或隐藏具有相同名称的成员函数和成员函数模板,parameter-type-list,cv-基类中的限定和ref限定符(如果有)(而不是冲突).这些隐藏或重写的声明被排除在using-declarator引入的声明集之外.


但是,当两个成员函数中的一个将其参数作为通用引用时,代码在所有主要编译器上编译良好.

当其中一个函数将其参数作为(转发)引用时,此模板函数不再被限定为隐藏,因为其参数类型列表不同.


OP打开了一个错误报告,检查出来:
错误87478 - 隐藏成员函数错误地参与限定名称查找.