中缀vs前缀语法:名称查找差异

Krz*_*icz 22 c++ syntax iostream operator-overloading

C++中的运算符通常被认为是函数/方法的替代语法,尤其是在重载的上下文中.如果是这样,下面的两个表达式应该是同义词:

std::cout << 42;
operator<<(std::cout, 42);
Run Code Online (Sandbox Code Playgroud)

实际上,第二个语句会导致以下错误:

call of overloaded ‘operator<<(std::ostream&, int)’ is ambiguous
Run Code Online (Sandbox Code Playgroud)

像往常一样,这样的错误信息附有可能的候选人名单,这些是:

operator<<(basic_ostream<_CharT, _Traits>& __out, char __c)
operator<<(basic_ostream<char, _Traits>& __out, char __c)
operator<<(basic_ostream<char, _Traits>& __out, signed char __c)
operator<<(basic_ostream<char, _Traits>& __out, unsigned char __c)
Run Code Online (Sandbox Code Playgroud)

这种错误至少引发了两个问题:

  1. 这两个语句以什么方式不同(在名称查找方面)?
  2. 为什么失踪?operator<<(basic_ostream<char, _Traits>& __out,int__c)

看起来,中缀和前缀符号不是完全可互换的 - 不同的语法需要不同的名称解析策略.有什么区别,它们来自哪里?

Igo*_*nik 16

不,这两个表达式不应该是同义词.std::cout << 42被查找既operator<<(std::cout, 42)std::cout.operator<<(42).两个查找产生可行的候选者,但第二个是更好的匹配.

  • @ 40two:最初的问题是为什么`std :: cout << 42`在`operator <<(std :: cout,42);`没有; 为什么两者不一样.答案是`std :: cout << 42`既可以解释为`operator <<(std :: cout,42)`也可以解释为`std :: cout.operator <<(42)`.编译器对两种形式执行两次名称查找,然后对两次查找找到的所有候选项执行重载解析.这就是为什么名称查找的差异对于手头的问题最重要的原因,而在两种情况之一中重载解析的失败是次要的. (3认同)
  • `operator <<()`是在命名空间`std`中通过ADL找到的运算符函数.采用整数的重载在那里找不到,但仅作为成员函数.这就是编译器将其列为模糊重载并且无法找到`operator <<(ostream&,int)`的原因. (2认同)