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

时间:2018-10-01 11:35:57

标签: c++ language-lawyer

我偶然发现了这个奇怪的名称查找问题,尽管基类成员函数是通过using语句导入的,但它似乎根本不参与重载选择。基类和派生类的成员函数都是SFINAE的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'
}

尽管GCC在没有警告的情况下编译了上面的代码,但是clang,icc和MSVC无法为d.create(0);的调用找到合适的重载并出错了。实际上,从错误消息来看,似乎Base::create甚至没有参与重载解决方案。

但是,当两个成员函数之一将其参数用作转发引用时,该代码可以在所有主要编译器上正常编译。

1 个答案:

答案 0 :(得分:5)

Gcc错误,应该拒绝您的示例。

using-declaration:
    using using-declarator-list ;
     

[namespace.udecl]/1

     在 using-declaration 中的每个 using-declarator 都会向在其中出现 using-declaration 的声明区域引入一组声明。 使用 using-declarator 引入的一组声明是通过对<<>中的名称执行合格的名称查找[basic.lookup.qual][class.member.lookup])来找到的。 em> using-declarator ,不包括如下所述隐藏的功能

排除的功能是:

  

[namespace.udecl]/15

     

using-declarator 将基类中的声明带入派生类时,派生类中的成员函数和成员函数模板将覆盖和/或使用相同的成员函数和成员函数模板隐藏它们基类中的名称,参数类型列表,cv限定符和ref限定符(如果有)(而不是冲突)。此类隐藏或覆盖的声明不包含在 using-declarator 引入的声明集中。


  

但是,当两个成员函数之一将其参数用作通用引用时,该代码可以在所有主要编译器上正常编译。

当函数之一将其参数用作(转发)引用时,此模板函数不再具有隐藏功能,因为其 parameter-type-list 不同。


OP已打开错误报告,请检出:
Bug 87478 - Hidden member function falsely takes part in qualified name lookup