Bjarne 对这个 ADL 示例的看法是错误的,还是我有一个编译器错误



我正在阅读关于参数依赖查找的C++编程语言,第 4 版(由 Bjarne Stroustrup 撰写(。这是引用(26.3.6,过度激进的ADL(:

依赖于参数的查找(通常称为 ADL(对于避免冗长 (14.2.4( 非常有用。例如:

#include <iostream>
int main()
{
    std::cout << "Hello, world" << endl; // OK because of ADL
}

如果没有依赖于参数的查找,将无法找到endl操纵器。实际上,编译器注意到要<<的第一个参数是 std 中定义的ostream。因此,它在std中查找endl并找到它(在<iostream>中(。

这是编译器(C++11 模式(生成的结果:

prog.cpp: In function ‘int main()’:
prog.cpp:4:36: error: ‘endl’ was not declared in this scope
 std::cout << "Hello, world" << endl;
                                ^
这要么是

编译器中的错误,要么是书中的错误。标准怎么说?

更新:

我需要澄清一点。我知道正确的答案是使用std::endl.问题是关于书中的文字。正如Lachlan Easton已经说过的那样,这不仅仅是一个错字。整个段落(可能(是错误的。如果这本书是另一位(鲜为人知的(作者,我可以接受这种错误,但我曾经(现在仍然(怀疑,因为它是由Bjarne写的。

这不是编译器中的错误。ADL 用于查找函数而不是参数operator<<是通过 ADL 通过查看参数 std::cout 和(应该是(std::endl 找到的函数。

对于那些说这是一个错字的人来说,事实并非如此。 要么是Bjarne犯了错误,要么是编译器错了。OP发布的段落之后的段落如下:

如果没有依赖于参数的查找,endl 操纵器就不会 发现。实际上,编译器注意到要<<的第一个参数是 在标准中定义的 ostream 。因此,它在 std 中查找 endl 和 找到它(在<iostream>(。

正如其他人已经指出的那样,这是书中的一个错字。然而,书中的意思是我们必须

std::operator<<(std::cout, "Hello, world").operator<<(std::endl);

没有 ADL。这就是Bjarne所说的冗长。


我站正了。正如拉克兰·伊斯顿(Lachlan Easton(指出的那样,这不是错字,而是书中的错误。我无法接触到这本书,这就是为什么我无法阅读那段并自己意识到它。我已经向Bjarne报告了这个错误,以便他能够纠正它。


有趣。同样的例子在维基百科上和

请注意,std::endl是一个函数,但它需要完全限定, 因为它被用作operator<<(std::endl是一个函数的参数 指针,而不是函数调用(。

毫无疑问,这是书中的一个错误。尽管如此,std::operator<<(std::cout, "Hello, world").operator<<(std::endl);示例显示了 ADL 如何帮助减少详细程度。


感谢gx_指出我的错误。

提示在名称"依赖于参数的查找"中。

它是对非限定函数名称的查找,其工作取决于参数

这与查找参数无关。

比亚恩说错了话。

我没有

这本书,但这似乎是书中的一个错误,它缺少命名空间限定符的事实与 ADL 无关。应该是std::endl.

是的,这是一个错误 - 该示例格式不正确,不应编译。 ADL 适用于引入函数调用表达式的非限定函数名称。 endl 是尝试查找std::endl 的 id 表达式。 endl 没有引入函数调用表达式,因此不对它使用依赖于参数的查找,只使用非限定查找,因此它不会按预期找到std::endl

一个更简单和正确的示例是:

#include <vector>
int main()
{
    std::vector<int> x, y;
    swap(x,y); // calls std::swap due to ADL
}

总之,在查找具有非限定id(例如f(的函数调用(例如f(x,y,z)(之前,首先分析函数的参数(例如x,y,z(以确定其类型。 关联命名空间的列表基于类型形成(例如,类型定义的封闭命名空间是关联的命名空间(。 然后,还会在这些命名空间中搜索函数。

Bjarne的例子的目的是炫耀std::operator<<函数的ADL,而不是std::endl。 这需要进一步了解重载运算符实际上是函数调用表达式,因此x << y表示operator<<(x,y),而operator<<是一个非限定名,因此 ADL 适用于它。 LHS 的类型std::ostream因此std是关联的命名空间,因此可以找到std::operator<<(ostream&, ...)

更正后的附言应为:

如果没有依赖于参数的查找,则不会找到 std 命名空间中重载的 << 运算符。实际上,编译器注意到要<<的第一个参数是在 std 中定义的 ostream。因此,它在 std 中查找运算符<<并找到它(在 <iostream> 中(。

相关内容

最新更新