Bjarne是否对ADL的示例有误,还是我遇到了编译器错误?


81

我正在阅读有关C ++编程语言的第四版(由Bjarne Stroustrup撰写),。这是报价(26.3.6,过度攻击性ADL):

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

#include <iostream>

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

如果没有依赖于参数的查找,endl将找不到操纵器。实际上,编译器会注意到to的第一个参数<<是在中ostream定义的std。因此,它endl在中std查找并找到它(在中<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撰写,所以我一直(并且仍然)对此表示怀疑。


12
std::endl没有错误
aaronman

3
以我的经验,书籍因错误和错别字而臭名昭著。希望在一本好书中只有次要/很明显。
尼尔·柯克

31
@aaronman OP显然知道这一点。从报价中可以看出,由于ADL ,Bjarne (C ++的创建者)声称std::在这种情况下不需要。但这不能编译,因此是个问题。
BlueRaja-Danny Pflughoeft13年

6
是的,重点是,这本书明确地说出了错误的话。这不是错字,而是写了整段文字来描述实际上不是真的。这是本书中的错误。
DanielKO 2013年

7
@maverik这书中的错误。我在几分钟前向他报告了此问题,我将让他知道他的答案。
阿里

Answers:


83

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


2
实际上,回想起来,这启发了一种通过利用以下事实使代码有效std::endl的方法:(事实上,令人困惑)函数:endl(std::cout << "Hello, world"); // OK because of ADL
alfC

49

对于那些说这是错别字的人,不是。Bjarne错误或编译器错误。OP发表的文章后的一段内容如下:

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


18
您的先生似乎是唯一真正在书上读过此书的人。这可能是语言规则的重大变化,使当前所有C ++编译器都变为非标准(对于C ++ 11),或者是Stroustrup先生的明显错误(而不仅仅是错字)。我宁愿再等两个月才能得到修订版。他最好留着胡子。
DanielKO 2013年

顺便说一句,标记吃了引号中的最后一位,您可能要使用反引号“(in <iostream>)”。
DanielKO

20

正如其他人已经指出的那样,这是本书中的错字。但是,这本书的意思是 我们必须写

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

没有ADL。这就是Bjarne冗长的意思。


我站得住了。正如Lachlan Easton指出的那样,这不是错别字,而是书中的错误。我没有这本书的使用权,这就是为什么我自己看不懂该段落的原因。我已将此错误报告给Bjarne,以便他可以纠正。


滑稽。Wikipedia

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

毫无疑问,这是本书中的错误。不过,该示例 std::operator<<(std::cout, "Hello, world").operator<<(std::endl);显示了ADL如何帮助减少冗长程度。


由于gx_指出我的错误


他不只是打字错误,他想了些什么(查找std::operator<<情况如何),并用错误的信息写了整个段落。这确实使您相信ADL规则已更改,并且编译器现在已损坏。
DanielKO

实际上,书中似乎有很多错别字,例如17.2.5
AndersK,2013年

@DanielKO我站得住了;我已确定答案,谢谢。我没有这本书的使用权,这就是为什么我认为这是错别字。无论如何,ADL确实有助于减少冗长,我给出的代码就是其中的一个例子。无论如何,谢谢你告诉我。
阿里

实际上,我们真正要写的是std::operator<<(std::cout, "Hello, world").operator<<(std::endl);(请参阅非成员operator<<成员operator<<
gx_13年

10

提示位于名称“依赖于参数的查找”中。

这是查找不合格的函数名称,该工程根据参数

它有没有关系查找参数。

比尼亚(Bjarne)失误。


8

我没有这本书,但是这似乎是本书中的一个错误,因为它缺少名称空间限定符与ADL无关。应该是std::endl


1
我同意。但这是一个很奇怪的陈述(我是说书中的那个)。我希望Bjarne应该对此有所了解。
maverik

@maverik也许他已经这样做了,如果有人已经报告了这个,我不会感到惊讶。如果没有,您可以:)
Borgleader

@maverik这实际上只是一个错字,我想别人已经注意到了它
aaronman

2
是的,是的,的确,我误解了std::cout他在说要搜索而operator<<不是的所有陈述endl
maverik

4

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

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

#include <vector>

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

总而言之,在查找f(x,y,z)具有不合格ID(例如f)的函数调用(例如)之前,请先查找该函数的参数(例如x,y,z要分析)以确定其类型。根据类型形成关联的名称空间列表(例如,类型定义的封闭名称空间是关联的名称空间)。然后,在这些名称空间中另外搜索功能。

Bjarne的示例的目的是展示该std::operator<<功能的ADL ,而不是std::endl。这需要额外的了解,重载的运算符实际上是函数调用表达式,因此x << ymeansoperator<<(x,y)operator<<都是不合格的名称,因此ADL适用于它。类型的LHS的是std::ostream这样std一个相关的命名空间,因此std::operator<<(ostream&, ...)被发现。

更正后的注释应显示为:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.