It recently came to my attention that member functions completely shadow free functions with the same name when inside the class. And by completely i mean that every free function with the same name is not considered for overload resolution at all. I can understand why it's done with somwthing like this:
最近我注意到,成员函数在类中完全使用同名的影子*函数。完全地,我的意思是,每个同名的*函数都不考虑重载解析。我能理解为什么要这么做:
void f();
struct S
{
void f();
void g()
{
f(); // calls S::f instead of ::f
}
};
where the functions have identical signatures, its only natural as variable scoping works the same way. But why prohibit unambigious calls where free function has different signature like this:
当函数具有相同的签名时,其唯一的自然变量范围是相同的。但是,为什么禁止在*函数有不同签名的情况下进行无矛盾的调用呢?
void f();
struct S
{
void f(int x);
void g()
{
f(); // fails to compile attempting to call S::f, which has wrong signature
}
};
I am not asking how to call a shadowed free function from inside the class. What i want to know is the rationale behind this design.
我并不是问如何从类内部调用一个阴影*函数。我想知道的是这个设计背后的原理。
3 个解决方案
#1
7
For unqualified name lookup, only one scope at a time is considered, and if the search in that scope doesn't yield any results, the next higher scope is searched. In your case, only S
's scope is searched.
对于不合格的名称查找,在一个时间内只考虑一个范围,如果在该范围内的搜索不产生任何结果,则搜索下一个更高的范围。在您的例子中,只搜索S的范围。
But why prohibit unambigious calls where free function has different signature like this:
但是,为什么禁止在*函数有不同签名的情况下进行无矛盾的调用呢?
The problem is that name lookup doesn't concern itself with anything but the name, the identifier. It is completely oblivious to the fact that you want to call a function, it just sees an identifier. The same name lookup happens if you just use auto x = f;
, and if you think of it that way, there are very good reasons you only want a very limited scope to search. Anything else would just surprise the user.
问题是,除了名称、标识符之外,名称查找不涉及任何内容。它完全没有注意到你想调用一个函数,它只看到一个标识符。如果您使用auto x = f,则会发生相同的名称查询;如果您这样想的话,那么您只需要一个非常有限的搜索范围,这是非常好的原因。其他任何东西都会让用户感到惊讶。
#2
3
There is a special, very surprising, rule (but it does not apply to your example) stating that once a class member name is found by name lookup, no namespace scopes are searched:
有一个特殊的、非常令人惊讶的规则(但它并不适用于您的示例)指出,一旦通过名称查找找到了类成员名称,就不会搜索名称空间作用域:
#include <string>
struct C {
std::string s;
explicit C (std::string);
void swap (C& rhs) {
swap (s, rhs.s); // error: swap is C::swap
}
};
void swap (C& lhs, C& rhs) {
swap (lhs.s, rhs.s); // std::swap(string,string)
}
IMO, this is craziness.
国际海事组织,这是疯狂。
But why prohibit unambigious calls where free function has different signature like this:
但是,为什么禁止在*函数有不同签名的情况下进行无矛盾的调用呢?
Name lookup happens before overloading resolution:
在重载解析之前进行名称查找:
- If lookup is ambiguous, overloading resolution is not done.
- 如果查找不明确,则不执行重载解析。
- If no viable function is found by name lookup, no other round of lookup is tried.
- 如果没有通过名称查找找到可行的函数,则不会尝试其他一轮查找。
The rules are sufficiently complex without "feedback" between overloading and name lookup. I would suggest simplification (like removing the member hides namespace scope name rule, and removing ambiguous name lookup) rather than complexification.
没有重载和名称查找之间的“反馈”,规则就足够复杂。我建议简化(比如删除成员隐藏名称空间范围名称规则,删除不明确的名称查找),而不是进行复化。
#3
2
I cannot provide an authoritative answer (Maybe some remember a quote from Design and Evolution of C++
or actually has been on the committee at that time), but my first guess would be to exactly fail in cases as you show. It is easy to forget how many things are in scope at a certain time. Additionally overload resolution can be quite complex and there can be default arguments and conversion. So I'd rather have the most limited scope in that case to be always sure what exactly is being called.
我不能给出一个权威的答案(也许有些人还记得c++的设计和演变,或者实际上当时我是委员会的一员),但我的第一个猜想是,在你所展示的情况下,肯定会失败。我们很容易忘记在某一时刻有多少事情是在范围内的。此外,重载解析可能非常复杂,可能存在默认参数和转换。所以我宁愿在这种情况下有最有限的范围来确定到底被调用了什么。
#1
7
For unqualified name lookup, only one scope at a time is considered, and if the search in that scope doesn't yield any results, the next higher scope is searched. In your case, only S
's scope is searched.
对于不合格的名称查找,在一个时间内只考虑一个范围,如果在该范围内的搜索不产生任何结果,则搜索下一个更高的范围。在您的例子中,只搜索S的范围。
But why prohibit unambigious calls where free function has different signature like this:
但是,为什么禁止在*函数有不同签名的情况下进行无矛盾的调用呢?
The problem is that name lookup doesn't concern itself with anything but the name, the identifier. It is completely oblivious to the fact that you want to call a function, it just sees an identifier. The same name lookup happens if you just use auto x = f;
, and if you think of it that way, there are very good reasons you only want a very limited scope to search. Anything else would just surprise the user.
问题是,除了名称、标识符之外,名称查找不涉及任何内容。它完全没有注意到你想调用一个函数,它只看到一个标识符。如果您使用auto x = f,则会发生相同的名称查询;如果您这样想的话,那么您只需要一个非常有限的搜索范围,这是非常好的原因。其他任何东西都会让用户感到惊讶。
#2
3
There is a special, very surprising, rule (but it does not apply to your example) stating that once a class member name is found by name lookup, no namespace scopes are searched:
有一个特殊的、非常令人惊讶的规则(但它并不适用于您的示例)指出,一旦通过名称查找找到了类成员名称,就不会搜索名称空间作用域:
#include <string>
struct C {
std::string s;
explicit C (std::string);
void swap (C& rhs) {
swap (s, rhs.s); // error: swap is C::swap
}
};
void swap (C& lhs, C& rhs) {
swap (lhs.s, rhs.s); // std::swap(string,string)
}
IMO, this is craziness.
国际海事组织,这是疯狂。
But why prohibit unambigious calls where free function has different signature like this:
但是,为什么禁止在*函数有不同签名的情况下进行无矛盾的调用呢?
Name lookup happens before overloading resolution:
在重载解析之前进行名称查找:
- If lookup is ambiguous, overloading resolution is not done.
- 如果查找不明确,则不执行重载解析。
- If no viable function is found by name lookup, no other round of lookup is tried.
- 如果没有通过名称查找找到可行的函数,则不会尝试其他一轮查找。
The rules are sufficiently complex without "feedback" between overloading and name lookup. I would suggest simplification (like removing the member hides namespace scope name rule, and removing ambiguous name lookup) rather than complexification.
没有重载和名称查找之间的“反馈”,规则就足够复杂。我建议简化(比如删除成员隐藏名称空间范围名称规则,删除不明确的名称查找),而不是进行复化。
#3
2
I cannot provide an authoritative answer (Maybe some remember a quote from Design and Evolution of C++
or actually has been on the committee at that time), but my first guess would be to exactly fail in cases as you show. It is easy to forget how many things are in scope at a certain time. Additionally overload resolution can be quite complex and there can be default arguments and conversion. So I'd rather have the most limited scope in that case to be always sure what exactly is being called.
我不能给出一个权威的答案(也许有些人还记得c++的设计和演变,或者实际上当时我是委员会的一员),但我的第一个猜想是,在你所展示的情况下,肯定会失败。我们很容易忘记在某一时刻有多少事情是在范围内的。此外,重载解析可能非常复杂,可能存在默认参数和转换。所以我宁愿在这种情况下有最有限的范围来确定到底被调用了什么。