我偶然发现了这个奇怪的名称查找问题,尽管基类成员函数是通过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
甚至没有参与重载解决方案。
但是,当两个成员函数之一将其参数用作转发引用时,该代码可以在所有主要编译器上正常编译。
答案 0 :(得分:5)
Gcc错误,应该拒绝您的示例。
using-declaration: using using-declarator-list ;
在 using-declaration 中的每个 using-declarator 都会向在其中出现 using-declaration 的声明区域引入一组声明。 使用 using-declarator 引入的一组声明是通过对<<>中的名称执行合格的名称查找(
[namespace.udecl]/1
[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。