[英]Why does endl(std::cout) compile
令人驚訝的是,以下代碼可以在各種編譯器和版本上編譯並正常運行。
#include <iostream>
int main() {
endl(std::cout);
return 0;
}
它如何編譯? 我確信全局范圍內沒有endl
,因為類似
std::cout << endl;
除非using
否則將失敗,否則您需要std::endl
。
此行為稱為自變量依賴查找或Koenig查找。 該算法告訴編譯器在查找不合格的函數調用時,不僅要查看本地范圍,還要查看包含參數類型的名稱空間。
例如:
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
}
關於問題文本中引用的那段代碼:
在std
名稱空間中聲明endl
或std::endl
,如下所示 :
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
聲明為
extern std::ostream cout;
因此調用std::endl(std::cout);
很好。
現在,當只調用endl(std::cout);
,因為參數cout
的類型來自std namespace
空間,所以可以在std
名稱空間中搜索到不合格的函數endl
,並成功找到該函數並確認它是一個函數,因此調用了合格的函數std::endl
。
進一步閱讀:
這是流操縱器的工作方式。 操縱器是作為參數傳遞給運算符<<的函數。 然后在運算符中將它們簡單地調用。
所以你有函數聲明像
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 <<
作為參數的函數指針。
在記錄中
std::endl( std::cout );
名稱endl
之前的名稱空間前綴可以省略,因為在這種情況下,編譯器將使用自變量依賴查找。 因此,這個記錄
endl( std::cout );
將成功編譯。
但是,如果將函數名稱括在括號中,則不使用ADL,並且以下記錄
( endl )( std::cout );
將不會編譯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.