中缀与前缀语法:名称查找差异
Infix vs prefix syntax: name lookup differences
操作符在c++中通常被认为是函数/方法的替代语法,特别是在重载上下文中。如果是这样,下面的两个表达式应该是同义的:
std::cout << 42;
operator<<(std::cout, 42);
实际上,第二个语句会导致以下错误:
call of overloaded ‘operator<<(std::ostream&, int)’ is ambiguous
通常,这样的错误消息伴随着一个可能的候选列表,它们是:
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)
这样的错误至少引起两个问题:
- 这两个语句在哪些方面不同(在名称查找方面)?
- 为什么
operator<<(basic_ostream<char, _Traits>& __out,
int
__c)
缺失?
看来,中缀和前缀符号不能完全互换——不同的语法需要不同的名称解析策略。它们的区别是什么?它们从何而来?
不,这两个表达式不应该是同义词。std::cout << 42
被查找为operator<<(std::cout, 42)
和std::cout.operator<<(42)
。这两种查找都产生可行的候选项,但第二个查找更匹配。
这些是c++ 17 [over.match]中的操作符查找规则。在这里,为了简洁起见,我删除了与重载operator<<
无关的文本,左操作数是一个类类型;并包含了一个部分,我将在后面解释:
对于二元操作符
@
,其左操作数的非限定版本为T1
,右操作数的非限定版本为T2
,有三组候选函数,指定为成员候选函数, 非成员函数候选项和内置候选项的构造方法如下:
- 如果
T1
是一个完整的类类型或一个正在定义的类,则候选成员集是T1::operator@
(16.3.1.1.1)的限定查找的结果;否则,候选成员集为空。- 非成员候选者集合是根据非限定函数调用中名称查找的通常规则在表达式上下文中对
operator@
进行非限定查找的结果,只是所有成员函数都被忽略。
内置候选者在这里为空,它指的是将隐式地将两个操作数转换为整数类型并应用位移位操作符的搜索函数;但是没有从iostreams到整型的隐式转换。
用于重载解析的候选函数集是成员候选函数、非成员候选函数和内置候选函数的并集。
操作符查找与其他函数查找的基本原理是什么?这意味着什么?我认为通过几个例子可以最好地回答这个问题。首先:
struct X{ operator int(); };
void f(X);
struct A
{
void f(int);
void g() { X x; f(x); } // Calls A::f
};
在这个例子中有一个原则:如果你试图从类的另一个成员函数调用类的一个成员函数;它应该明确地找到成员函数,而不是让搜索被外部函数(甚至包括ADL)污染。
因此,非限定查找规则的一部分是,如果查找的非ADL部分找到一个类成员函数,则不执行ADL。
如果没有这个规则,f(x)
会同时找到A::f
和::f
,然后重载解析会选择::f
作为更好的匹配,这是我们不希望的。
到第二个例子:
struct X{};
std::ostream& operator<<(std::ostream&, X);
struct S
{
std::ostream& operator<<(int);
void f()
{
X x;
std::cout << x; // OK
// operator<<(std::cout, x); // FAIL
// std::cout.operator<<(x); // FAIL
}
};
按照前面示例的原则—如果规则只是将std::cout << 42;
转换为operator<<(std::cout, 24);
,则名称查找将找到S::operator<<
并停止。哎呀!
所以我认为说上面OK
行的行为来自标记为FAIL
的两行是不太正确的,正如其他答案/评论所建议的那样。
简介:
现在我们可以理解我的答案顶部的标准报价的实际措辞了。
代码std::cout << x;
将:
- 查找
std::cout.operator<<(x);
AND - 查找
operator<<(std::cout, x)
,除非成员函数被忽略(因此,由于成员函数被发现,没有adl抑制)。
则对这两个集合的并集执行重载解析。
- 正在查找文档以获得PS4平台的C++中的设备信息
- 在C++中查找文件
- 模板元程序查找相似的连续类型名称
- 在UNIX系统中使用DIR查找文件的字节大小
- 查找最接近的大于当前数字的数字的索引
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 查找后更改类变量
- 使用正则表达式regex_search在字符串中查找字符串
- 使用gcc从静态链接的文件中查找可选符号
- 在C++中查找范围的长度
- 算法问题:查找从堆栈中弹出的所有序列
- 查找带有 Anaconda cmake 前缀的 boost-python3
- 查找可能的前缀回文
- 为带有带前缀的字符串的容器查找相等的范围
- 使用std :: quare_range查找字符串向量中发生的前缀范围
- 查找有序STL容器中以前缀开头的所有字符串(非低位ASCII)
- 具有最近路径前缀回退的查找树
- 查找字典中包含的最长前缀
- C++模糊解算器:在集合中查找前缀
- 中缀与前缀语法:名称查找差异