Почему вывод типа для std::endl не работает?

В следующем коде:

#include <iostream>

auto& print = std::cout; // Type deduction for std::cout works
auto& end = std::endl;   // But the std::endl is exception here

int main(void) {
  print << "Hello" << end;

  return 0;
}

Вывод типа для std::cout происходит правильно, но почему он не работает для std::endl?

Примечание. Удаление ссылки на оператор (амперсанд) также не работает.


Код VS гласит:

Снимок экрана с ошибкой вывода типа

И компилятор генерирует следующее:

$ g++ -Wall -O3 -std=c++14 -o main main.cpp; ./main

main.cpp:4:18: error: unable to deduce 'auto&' from 'std::endl'
    4 | auto& end = std::endl;    // But the std::endl is exception here
      |                  ^~~~
main.cpp:4:18: note:   couldn't deduce template parameter 'auto'

person Rohan Bari    schedule 09.08.2020    source источник
comment
Вы действительно не должны пытаться переименовывать стандартные библиотечные конструкции таким образом.   -  person Nicol Bolas    schedule 09.08.2020
comment
@NicolBolas Я понимаю это. Я был так сбит с толку, когда увидел, что он работает с std::cout, но не с std::cin. Искал об этом, но, похоже, я не нашел что-то актуальное по этой проблеме.   -  person Rohan Bari    schedule 09.08.2020
comment
Вы написали этот код на основе этого вопроса? В частности, этот ответ, который показывает трюк auto& print = std::cout;, но также говорит Поскольку std::endl является шаблонной функцией, а не тип, его нельзя вывести, используя ссылку на auto тип.   -  person Remy Lebeau    schedule 09.08.2020
comment
@RemyLebeau Да, я написал это, как только понял причину. И это были странные вещи, которые std::endl в тот раз не сработали. Я понятия не имел об этом.   -  person Rohan Bari    schedule 09.08.2020
comment
В большинстве случаев вам не нужно std::endl. auto end = '\n' будет работать так же хорошо (и вы можете просто написать "Hello\n").   -  person Artyer    schedule 09.08.2020
comment
НЕ публикуйте изображения кода, данных, сообщений об ошибках и т. д. — скопируйте или введите текст в вопрос. Как спросить   -  person Rob    schedule 03.03.2021
comment
Отвечает ли это на ваш вопрос? Можем ли мы переименовать ключевое слово cout, endl в cpp?   -  person Casey    schedule 03.03.2021


Ответы (1)


std::cout — это объект конкретного типа std::ostream (он же специализация std::basic_ostream<char>), поэтому auto может вывести его тип.

std::endl — это вообще не объект, это шаблонная функция (в частности, манипулятор потока, принимающий шаблонный объект std::basic_ostream в качестве параметра):

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

Будучи шаблоном, std::endl позволяет работать с потоками вывода различных типов символов (char, wchar_t и т. д.), т. е. std::cout против std::wcout и т. д.

Но вы не предоставляете никаких значений для параметров шаблона, чтобы сообщить компилятору, какую специализацию std::endl вы хотите использовать, поэтому auto не может вывести для него конкретный тип, отсюда и ошибка.

Вместо этого вам нужно было бы сделать что-то вроде этого:

auto& end = std::endl<char, std::char_traits<char>>;

Текущая демонстрация

person Remy Lebeau    schedule 09.08.2020
comment
@RohanBari шаблоны — очень сложная тема, есть целые главы и даже целые книги на эту тему. Я настоятельно рекомендую вам приобрести несколько хороших книг по C++ для чтения. - person Remy Lebeau; 09.08.2020