【问题标题】:Why does endl(std::cout) compile为什么 endl(std::cout) 编译
【发布时间】:2015-03-27 07:03:13
【问题描述】:

令人惊讶的是,下面的代码在各种编译器和版本上编译和运行都没有错误。

#include <iostream>

int main() {
    endl(std::cout);
    return 0;
}

Ideone link

它是如何编译的?我确信在全球范围内没有endl,因为像

这样的代码
std::cout << endl;

除非使用using,否则您需要std::endl,否则会失败。

【问题讨论】:

标签: c++ argument-dependent-lookup


【解决方案1】:

这种行为称为argument dependent lookup 或 Koenig 查找。该算法告诉编译器不仅要查看本地范围,还要查看包含参数类型的命名空间,同时查找 unqualified 函数调用。

例如:

namespace foo {
  struct bar{
    int a;
  };

  void baz(struct bar) {
    ...
  }
};

int main() {
  foo::bar b = {42};
  baz(b);  // Also look in foo namespace (foo::baz)
  // because type of argument(b) is in namespace foo
}

关于问题文本中提到的那段代码:

endlstd::endlstd 命名空间 as following 中声明:

template< class CharT, class Traits >
std::basic_ostream<charT,traits>&     endl( std::basic_ostream<CharT, Traits>& os );

std::ostream& endl (std::ostream& os);

coutstd::coutdeclared as

extern std::ostream cout;

所以调用std::endl(std::cout); 完全没问题。

现在当一个人只调用endl(std::cout);时,因为参数cout的类型来自std namespace,所以在std命名空间中搜索一个函数endl是不合格的,它被成功找到并确认是一个函数,因此调用了合格的函数std::endl


进一步阅读:

  1. GOTW 30: Name Lookup

  2. Why does 'std::endl' require the namespace qualification when used in the statement 'std::cout << std::endl;", given argument-dependent lookup?

【讨论】:

    【解决方案2】:

    这是流操纵器的工作方式。 操纵器是作为参数传递给运算符

    所以你的函数声明如下

    template <class charT, class traits>
    basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);
    

    并将其指针传递给运算符 的操作符内部

    ostream& ostream::operator << ( ostream& (*op)(ostream&));
    

    函数被调用.like

    return (*endl )(*this);
    

    因此当你看到记录时

    std::cout << std::endl;
    

    那么std::endl 是作为参数传递给operator &lt;&lt; 的函数指针。

    在记录中

    std::endl( std::cout );
    

    名称endl 之前的名称空间前缀可以省略,因为在这种情况下,编译器将使用参数相关查找。因此这个记录

    endl( std::cout );
    

    会编译成功。

    但是,如果将函数名括在括号中,则不使用 ADL 并且以下记录

    ( endl )( std::cout );
    

    不会编译。

    【讨论】:

    • 我认为问题在于为什么函数调用表单上不需要std::
    • @Matt McNabb 我重读了这篇文章,看来你是对的。:)
    猜你喜欢
    • 2017-05-13
    • 1970-01-01
    • 2020-07-23
    • 2020-03-19
    • 1970-01-01
    • 2012-01-08
    • 1970-01-01
    • 2021-08-04
    相关资源
    最近更新 更多