首页 > 解决方案 > enable_if 继承的成员函数的名称查找错误

问题描述

我偶然发现了这个奇怪的名称查找问题,其中基类成员函数似乎根本不参与重载选择,即使它是通过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甚至没有参与重载解决方案。

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

标签: c++language-lawyer

解决方案


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

using-declaration:
    using using-declarator-list ;

[namespace.udecl]/1

using-declaration中的每个using- declarator都将一组声明引入到using-declaration出现的声明性区域中。通过对 using-declarator中的名称执行限定名称查找( , ) 来找到由using- declarator 引入的声明集包括如下所述的隐藏函数[basic.lookup.qual][class.member.lookup]

排除的功能是:

[namespace.udecl]/15

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


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

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


OP 已打开一个错误报告,请查看:
错误 87478 - 隐藏的成员函数错误地参与了限定名查找


推荐阅读