70

次のようなコード行ではstd::coutなく、なぜ書く必要があるのですか。std::<<

#include <iostream>

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

coutstdライブラリから来て、<<通常はビットシフトには使用されませんか? では、スコープ演算子は別の意味でも使用されるため、の::前にも書く必要がないのはなぜですか? after が別のことを意味する<<ことをコンパイラがどのように認識するのでしょうか?std::cout<<

4

3 に答える 3

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*);

は namespace で宣言されていますstd。この名前空間は の型に関連付けられているstd::coutため、この関数が見つかります。

std::ostreamは単なる typedef でstd::basic_ostream<char, std::char_traits<char>>あり、15 の配列はconst charchar const*(配列の最初の要素を指す) に暗黙的に変換できます。したがって、この関数は 2 つの引数型で呼び出すことができます。

のオーバーロードは他にもありますが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
}

注: この関数は演算子であるため、実際のルックアップはもう少し複雑です。これは、最初の引数 (クラス型の場合) のスコープ内で修飾ルックアップを介して、つまりメンバー関数としてルックアップされます。さらに、修飾されていないルックアップが実行されますが、すべてのメンバー関数が無視されます。非修飾ルックアップは実際には 2 段階の手順に似ており、引数依存のルックアップが 2 番目のステップであるため、結果はわずかに異なります。最初のステップでメンバ関数が見つかった場合、2 番目のステップは実行されません。つまり、引数依存のルックアップは使用されません

比較:

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
    }
}
于 2013-10-01T17:52:58.380 に答える
9

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

これは、引数依存の名前検索 (ADL、別名Koenig Lookup )で実現されます。

修飾子は 1 つしかありませんが、名前空間stdから生じるものが 2 つあります。std

  • cout
  • <<

ADL なし (Koenig Lookup)

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

コンパイルするには、より醜い形で使用する必要があります

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

したがって、このような醜い構文を回避するには、Koenig Lookup を高く評価する必要があります :)

于 2013-10-01T17:49:48.587 に答える