为什么我要编写std :: cout而不是std ::<<

时间:2013-10-01 17:41:37

标签: c++

为什么我必须在这样的代码行中编写std::cout而不是std::<<

#include <iostream>

int main() {
    std::cout << "Hello, world!";
    return 0;
}

cout来自std库,通常不会<<进行位移?那么,为什么我不必在::之前编写范围运算符<<,因为它也用于其他含义?编译器如何知道std::cout后,<<意味着另一件事?

3 个答案:

答案 0 :(得分:55)

首先,编译器将查看<<左侧和右侧的类型。 std::cout的类型为std::ostream,字符串文字的类型为 15 const char 的数组。由于左边是类类型,它将搜索名为operator<<的函数。问题是,它看起来会在哪里?

查找此名称operator<<是一种所谓的非限定查找,因为函数名称不像std::operator<<那样限定。函数名称的非限定查找会调用依赖于参数的查找。依赖于参数的查找将搜索与参数类型相关联的类和名称空间。

当您加入<iostream>时,签名的免费功能

template<typename traits>
std::basic_ostream<char, traits>& operator<<(std::basic_ostream<char, traits>&,
                                             const char*);

已在名称空间std中声明。此命名空间与std::cout的类型相关联,因此将找到此函数。

std::ostream只是std::basic_ostream<char, std::char_traits<char>>的typedef,15 const char数组可以隐式转换为char const*(指向数组的第一个元素)。因此,可以使用两种参数类型调用此函数。

还有operator<<的其他重载,但我上面提到的函数是参数类型和本例中选择的函数的最佳匹配。


依赖于参数的查找的简单示例:

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
}

N.B。由于此函数是运算符,因此实际查找更复杂一些。它通过第一个参数范围内的限定查找(如果是类类型)查找,即作为成员函数。 另外,执行非限定查找,但忽略所有成员函数。结果略有不同,因为不合格的查找实际上就像一个两步过程,其中依赖于参数的查找是第二步。如果第一步找到成员函数,则不执行第二步,即依赖于参数的查找使用。

比较

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
    }
}

答案 1 :(得分:9)

std::cout << "Hello, world!"; //calls std:::operator <<

这是通过依赖于参数的名称查找(ADL,又名Koenig Lookup

来实现的

虽然我们只有一个std限定符,但std命名空间有两件事情

  • cout
  • <<

没有ADL,(Koenig Lookup)

std::cout std:: << "Hello World" ;//this won't compile

为了编译它,我们需要使用它更加丑陋的形式

std::operator<<(std::cout, "Hello, world!");

为了避免这种丑陋的语法,我们必须欣赏Koenig Lookup:)

答案 2 :(得分:3)

编译器看到&lt;&lt;的参数是一个std :: ostream对象和一个字符串,因此能够找到合适的运算符&lt;&lt;基于此的定义。

您可以将运算符(或实际上,任何函数)的参数类型视为其名称的一部分。