Why does endl(std::cout) compile

旧街凉风 提交于 2019-12-02 20:41:50
Gyapti Jain

This behavior is called argument dependent lookup or Koenig lookup. This algorithm tells the compiler to not just look at local scope, but also the namespaces that contain the argument's type while looking for unqualified function call.

For ex:

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
}

About the piece of code referred in question text:

endl or std::endl is declared in std namespace as following:

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

or

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

And cout or std::cout is declared as

extern std::ostream cout;

So calling std::endl(std::cout); is perfectly fine.

Now when one calls just endl(std::cout);, because the type of argument cout is from std namespace, unqualified supposedly a function endl is searched in std namespace and it is found succesfully and confirmed to be a function and thus a call to qualified function std::endl is made.


Further reading:

  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?

It is the way the stream manipulators work. Manipulators are functions that passed to operator << as arguments. Then within the operator they are simply called.

So you have function declared like

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

and you pass its pointer to operator <<. And inside the operator that declared something like

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

the function is called.like

return (*endl )(*this);

Thus when you see record

std::cout << std::endl;

then std::endl is function pointer that is passed to the operator << as argument.

In the record

std::endl( std::cout );

namespace prefix before name endl may be omitted because in this case the compiler will use the Argument Dependent Lookup. Thus this record

endl( std::cout );

will compile successfully.

However if to enclose the function name in parentheses then ADL is not used and the following record

( endl )( std::cout );

will not compiled.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!