c++ - 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
甚至没有参与重载解决方案。
但是,当两个成员函数之一将其参数作为转发引用时,代码在所有主要编译器上都可以正常编译。
解决方案
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 - 隐藏的成员函数错误地参与了限定名查找。
推荐阅读
- javascript - 如何删除 div 和 div 内的所有元素?Javascript、HTML、CSS
- google-sheets-formula - 我需要拆分谷歌表格单元格中的值
- c# - 枚举的意外行为
- reactjs - React Native 子组件未在 onPress 事件上呈现
- javascript - 向注入的项目类添加构造函数
- c# - 如何在项目中使用多个实体框架连接字符串?
- c++ - 带有 enable_if 或类似内容的模板结构标记部分特化
- python - Dialogflow python 客户端版本控制
- java - 是否可以在 amazon kinesis 消费者库 v2 中禁用 SSL 证书检查?
- android - 创建带有透明圆圈的视图