为什么我必须写std :: cout而不是std :: <<
为什么我必须在这样的代码行中编写std::cout
而不是std::<<
:
#include <iostream> int main() { std::cout << "Hello, world!"; return 0; }
cout
来自std
库,而不是<<
通常用于位移的? 那么,为什么我不必在<<
之前写作域操作符::
因为它也被用于另一个含义? 编译器如何知道在std::cout
, <<
意味着另一件事情?
首先,编译器会查看<<
左右的types。 std::cout
的types是std::ostream
,string的数组types是15个const char
。 由于左边是types,它将search名为operator<<
的函数。 问题是,它在哪里看?
这个名称operator<<
的查找是一个所谓的非限定查找,因为函数名称不像std::operator<<
。 函数名称的非限定查找会调用依赖于参数的查找。 参数相关的查找将在与参数types相关联的类和名称空间中进行search。
当你包含<iostream>
,签名的一个自由function
template<typename traits> std::basic_ostream<char, traits>& operator<<(std::basic_ostream<char, traits>&, const char*);
已经在namespace std
声明了。 这个命名空间与std::cout
的types相关联,因此可以find这个函数。
std::ostream
只是std::basic_ostream<char, std::char_traits<char>>
一个typedef std::basic_ostream<char, std::char_traits<char>>
,并且可以将15个const char
的数组隐式转换为char const*
(指向数组的第一个元素)。 所以这个函数可以用两个参数types来调用。
还有operator<<
其他重载,但是我上面提到的函数是参数types和在这种情况下select的参数types的最佳匹配。
参数相关查询的一个简单例子:
namespace my_namespace { struct X {}; void find_me(X) {} } int main() { my_namespace::X x; find_me(x); // finds my_namespace::find_me because of the argument type }
注意由于这个函数是一个操作符,所以实际的查找有点复杂。 它在第一个参数(如果是类types的)范围内通过合格的查找来查找,即作为成员函数。 此外 ,执行不合格的查找,但忽略所有成员函数。 结果稍有不同,因为不合格的查找实际上就像是一个两步过程,依赖于参数的查找是第二步。 如果第一步find一个成员函数,则不执行第二步,即不使用参数相关查找。
比较:
namespace my_namespace { struct X { void find_me(X, int) {} void search(); }; void find_me(X, double) {} void X::search() { find_me(*this, 2.5); // only finds X::find_me(int) // pure unqualified lookup (1st step) finds the member function // argument-dependent lookup is not performed } }
至:
namespace my_namespace { struct X { void operator<<(int) {} void search(); }; void operator<<(X, double) {} void X::search() { *this << 2.5; // find both because both steps are always performed // and overload resolution selects the free function } }
在std::cout << "Hello, world!"; //calls std:::operator <<
std::cout << "Hello, world!"; //calls std:::operator <<
这是通过依赖于参数的名称查找(ADL,又名Koenig查找 )
虽然我们只有一个std
限定符,但是有两个东西来自std
命名空间
-
cout
-
<<
没有ADL,(Koenig Lookup)
std::cout std:: << "Hello World" ;//this won't compile
为了编译它,我们需要使用它更丑陋的forms
std::operator<<(std::cout, "Hello, world!");
所以为了避免这样丑陋的语法,我们必须欣赏Koenig Lookup 🙂
编译器看到<<的参数是一个std :: ostream对象和一个string,所以能够根据这个定义合适的operator <<定义。
您可以将运算符的参数types(或者真的,任何函数)作为其名称的一部分。