为什么 endl(std::cout) 编译
Why does endl(std::cout) compile
令人惊讶的是,下面的代码在各种编译器和版本上编译和运行都没有错误。
#include <iostream>
int main() {
endl(std::cout);
return 0;
}
它是如何编译的?我确定在全局范围内没有 endl
因为像
这样的代码
std::cout << endl;
会失败,除非使用 using
否则你需要 std::endl
.
此行为称为 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
}
关于问题文本中提到的代码片段:
endl
或 std::endl
在 std
命名空间 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);
而cout
或std::cout
是declared as
extern std::ostream cout;
所以调用 std::endl(std::cout);
完全没问题。
现在当调用 endl(std::cout);
时,因为参数类型 cout
来自 std namespace
,不合格的函数 endl
在 [=16= 中搜索] 命名空间,它被成功找到并确认是一个函数,因此调用了合格函数 std::endl
。
进一步阅读:
Why does 'std::endl' require the namespace qualification when used in the statement 'std::cout << std::endl;", given argument-dependent lookup?
这是流操纵器的工作方式。
操纵符是作为参数传递给 operator << 的函数。然后在运算符中简单地调用它们。
所以你的函数声明为
template <class charT, class traits>
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);
然后你将它的指针传递给运算符<<。在声明类似
的运算符内部
ostream& ostream::operator << ( ostream& (*op)(ostream&));
函数是called.like
return (*endl )(*this);
因此当你看到记录时
std::cout << std::endl;
然后 std::endl
是作为参数传递给 operator <<
的函数指针。
在记录中
std::endl( std::cout );
名称 endl
之前的 命名空间前缀可以省略,因为在这种情况下编译器将使用参数相关查找。因此这个记录
endl( std::cout );
将编译成功。
但是,如果将函数名称括在括号中,则不使用 ADL 并记录以下内容
( endl )( std::cout );
不会编译。
令人惊讶的是,下面的代码在各种编译器和版本上编译和运行都没有错误。
#include <iostream>
int main() {
endl(std::cout);
return 0;
}
它是如何编译的?我确定在全局范围内没有 endl
因为像
std::cout << endl;
会失败,除非使用 using
否则你需要 std::endl
.
此行为称为 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
}
关于问题文本中提到的代码片段:
endl
或 std::endl
在 std
命名空间 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);
而cout
或std::cout
是declared as
extern std::ostream cout;
所以调用 std::endl(std::cout);
完全没问题。
现在当调用 endl(std::cout);
时,因为参数类型 cout
来自 std namespace
,不合格的函数 endl
在 [=16= 中搜索] 命名空间,它被成功找到并确认是一个函数,因此调用了合格函数 std::endl
。
进一步阅读:
Why does 'std::endl' require the namespace qualification when used in the statement 'std::cout << std::endl;", given argument-dependent lookup?
这是流操纵器的工作方式。 操纵符是作为参数传递给 operator << 的函数。然后在运算符中简单地调用它们。
所以你的函数声明为
template <class charT, class traits>
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);
然后你将它的指针传递给运算符<<。在声明类似
的运算符内部ostream& ostream::operator << ( ostream& (*op)(ostream&));
函数是called.like
return (*endl )(*this);
因此当你看到记录时
std::cout << std::endl;
然后 std::endl
是作为参数传递给 operator <<
的函数指针。
在记录中
std::endl( std::cout );
名称 endl
之前的 命名空间前缀可以省略,因为在这种情况下编译器将使用参数相关查找。因此这个记录
endl( std::cout );
将编译成功。
但是,如果将函数名称括在括号中,则不使用 ADL 并记录以下内容
( endl )( std::cout );
不会编译。