簡體   English   中英

“ std :: cout << std :: endl;”如何編譯?

[英]How does “std::cout << std::endl;” compile?

大多數IO流操縱器是具有以下簽名的常規功能:

std::ios_base& func( std::ios_base& str );

但是,某些操縱器(包括最常用的操縱器std::endlstd::flush )是以下形式的模板:

template< class CharT, class Traits >
std::basic_ostream<CharT, Traits>& func(std::basic_ostream<CharT, Traits>& os);

然后,如何編譯std::cout << std::endl; 鑒於以下示例失敗,成功:

$ cat main.cpp 
#include <iostream>

int main()
{
    auto myendl = std::endl;
    std::cout << myendl;
}

$ g++ -std=c++11    main.cpp   -o main
main.cpp: In function ‘int main()’:
main.cpp:5:24: error: unable to deduce ‘auto’ from ‘std::endl’
     auto myendl = std::endl;
                        ^

顯然,上下文(在std::cout << std::endl; )有助於編譯器消除對std::endl的引用的歧義。 但是,控制該程序的規則是什么? 對於超載分辨率而言,這似乎是一個真正的挑戰,它必須立即回答兩個問題:

  1. std::endl指的是std::endl<CharT, Traits>()哪個專業化?
  2. operator<<指的是哪個功能?

模板自變量推導(1)應該在重載解決方案(2)之前發生,但是似乎(2)的至少一部分必須執行才能使(1)成功。


一些相關但絕非重復的問題是:

這些問題都沒有,也沒有答案解決模板參數推導的工作,這種推導應該在重載解析之前,但必須得到后者的幫助。


后續問題: 當參數是重載函數時,重載解析如何工作?

有問題的operator<<std::basic_ostream成員

namespace std {
    template <class charT, class traits = char_traits<charT> >
    class basic_ostream {
    public:
        basic_ostream<charT,traits>& operator<<(
          basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));
        // ...
    };
}

由於調用是std::cout << std::endl或等效的std::cout.operator<<(std::endl) ,我們已經知道basic_ostream的確切實例: std::basic_ostream<char, std::char_traits<char>> ,又名std::ostream 所以cout的成員函數看起來像

std::ostream& operator<<(std::basic_ostream<char, std::char_traits<char>>& (*pf)
    (std::basic_ostream<char, std::char_traits<char>>&));

該成員函數不是函數模板,而只是普通成員函數。 所以剩下的問題是,是否可以使用名稱std::endl作為參數來調用它? 是的,初始化函數參數等效於變量初始化,就像我們已經寫過一樣

std::basic_ostream<char, std::char_traits<char>>& (*pf)
    (std::basic_ostream<char, std::char_traits<char>>&) = std::endl;

因為basic_ostream具有operator<<的模板重載,所以basic_ostream需要這樣的函數指針:

basic_ostream<charT, traits>& operator<<(basic_ios<charT, traits>& (*pf)(basic_ios<charT, traits>&));

給定一個形式的語句表達

 std::cout << std::endl;

編譯器具有有關std::cout類型的信息-這是模板化std::basic_ostream的特殊化,其外觀類似於(省略包含的namespace std )。

template <class charT, class traits = char_traits<charT> >
    class basic_ostream
{
    public:
        basic_ostream<charT,traits>& operator<<(
            basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));
};

由於編譯器具有有關std::cout的類型的信息,因此它知道專用於charT模板的charTtraits是什么。

上述原因std::endl中表達std::cout << std::endl以匹配特定std::basic_ostream<charT, traits>& endl( std::basic_ostream<charT, traits>&)

原因類型推論不適用於

 auto myendl = std::endl;

這是因為std::endl是模板函數,並且此聲明未提供專門用於該模板的信息(即,選擇什么charTtraits )。 如果不能專用於模板化的std::endl ,則無法推斷該函數的返回類型,因此類型推導失敗。

您需要將<<放在endl之前。 它是ofstream的成員:

namespace std {
template <class charT, class traits = char_traits<charT> >
class basic_ostream {
public:
    basic_ostream<charT,traits>& operator<<(
      basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));
    // ...
};

}

endl就像“ / n”一樣跳過該行,因此您需要一個cout行來跳過

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM