类外功能重载未见
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了类外功能重载未见相关的知识,希望对你有一定的参考价值。
考虑以下代码片段。
enum class Bar {
A
};
void foo(Bar) {}
struct Baz {
void foo() {
foo(Bar::A);
}
};
编译失败,gcc9.2的信息是:
:12:19: error: no matching function for call to 'Baz::foo(Bar)'
12 | foo(Bar::A);
|
我不怀疑这是一个bug,因为clang 10也失败了。对于这种情况,我有两个问题。
标准在哪里定义了这种重载的行为?
编译器的行为被这样定义的原因是什么?
根据非限定名查找规则,从标准。[basic.lookup.unqual]1,
(重点是我)
在[basic.lookup.unqual]中列出的所有情况下,作用域都会按照各自类别中列出的顺序搜索声明。一旦找到了name的声明,name查找就会结束。.
这意味着这个名字 foo
是在类的作用域中找到的(即在 Baz::foo
本身),那么名称查找就会停止;全局的名称不会被找到,也不会被考虑到后面发生的重载解决。
关于你的第2个问题,函数不能通过不同的作用域进行重载,这可能会造成不必要的混乱和复杂。请看下面的代码。
struct Baz {
void foo(int i) { }
void foo() {
foo('A');
}
};
你知道 'A'
将转换为 int
然后传给 foo(int)
,这很好。如果允许函数通过作用域重载,如果有一天一个 foo(char)
在全局范围内被某个人或库添加,代码的行为会发生改变,这是很混乱的,特别是当你不知道添加全局的时候。
调用 foo
里面 Baz::foo()
只会查询类内的名称。如果您想使用 foo
类外声明 Baz
,你需要使用作用域解析运算符,像这样。
enum class Bar {
A
};
void foo(Bar) {}
struct Baz {
void foo() {
::foo(Bar::A); // looks up global 'foo'
}
};
请注意,对 foo
失败,因为有一个 Bar::foo
在最接近的作用域中找到。如果你以不同的方式命名函数,那么在最近的作用域中就找不到任何函数。Bar
,编译器会在外部作用域中查找该函数。
enum class Bar {
A
};
void foo(Bar) {}
struct Baz {
void goo() { // not 'foo'
foo(Bar::A); // this is fine, since there is no 'Bar::foo' to find
}
};
以下是引用自 cppreference 对于 类定义.
e) 如果这个类是一个命名空间的成员,或者是嵌套在一个命名空间成员的类中,或者是一个命名空间成员的函数中的一个局部类,则会搜索命名空间的范围,直到该类、包围类或函数的定义,如果查找的是一个友情声明引入的名字:这种情况下只考虑最里面的包围命名空间,否则照样继续查找包围命名空间,直到全局范围。
当然,这只适用于类定义,但对于 成员功能 (这是你的例子),它说
对于成员函数体内部使用的名称、成员函数的默认参数、成员函数的异常规范或默认成员初始化器,搜索的作用域与[类定义]中相同,......。
所以同样的逻辑也适用。
以上是关于类外功能重载未见的主要内容,如果未能解决你的问题,请参考以下文章