Мы знаем это endl
это манипулятор и внутренне это поставить '\n'
в буфер, а затем очистить буфер. Где endl
определены? Что такое endl
это макрос или функция, или переменная, или класс, или объект? Как я могу определить свой собственный endl
Манипулятор?
cout << "hello" << endl ; /*what is endl and where it is defined */
std::endl
это шаблон функции подписи:
template<class CharT, class Traits>
std::basic_ostream<CharT,Traits>& endl(std::basic_ostream<CharT,Traits>&);
std::basic_ostream::operator<<
перегрузка std::basic_ostream<CharT,Traits>>::operator<<(std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&))
принимает функцию определенной подписи.
Когда вы делаете std::cout << std::endl
, разрешение перегрузки сделано на std::endl
, который определяет правильные типы шаблонов для std::endl
и создает функцию. Затем он превращается в указатель и передается operator<<
,
std::basic_ostream::operator<<
затем вызывает функцию для рассматриваемого ostream и возвращает возвращаемое значение. Что-то вроде:
template<class CharT, class Traits>
std::basic_ostream<CharT, Traits>&
std::basic_ostream<CharT, Traits>::operator<<(
std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&)
) {
return func(*this);
}
Но точная реализация зависит от автора библиотеки компилятора1.
std::endl
заставляет печатать новую строку, а затем сообщает ostream о необходимости очистить себя. Вы можете подражать делать std::cout << std::endl;
через эти две строки кода:
std::cout.put(std::cout.widen('\n'));
std::cout.flush();
Как именно std::endl
Реализовано ли это до компилятора, но приведенное выше примерное приближение того, как вы могли бы написать его (естественно, в общем потоке).
Вы гарантированно имеете доступ к std::endl
если ты #include <ostream>
, Вы можете иметь к нему доступ, если вы включите любой другой заголовочный файл из std
библиотека. Какой файл точно определяет, это снова зависит от реализации.
std::endl
известен как «манипулятор IO». Этот метод предназначен для того, чтобы позволить функциям, управляющим состоянием потока io, быть «встроенными» с выходными командами путем создания цепочки <<
звонит вместе.
Чтобы создать свой собственный, если вы хотите, чтобы он работал с одним типом ostream, просто создайте функцию, которая принимает такого рода ostream
по ссылке, и возвращает его по ссылке. Теперь это манипулятор.
Если вы хотите обработать набор потоков, создайте шаблон как:
template<class CharT, class Traits>
std::basic_ostream<CharT, Traits>& bob(std::basic_ostream<CharT, Traits>& os)
{
return os << os.widen('b') << os.widen('o') << os.widen('b');
}
который теперь IO манипулятор, который печатает "bob"
, Он может делать что угодно с basic_ostream
обсуждаемый.
Альтернативный план такой:
struct bob_t {
template<class OS>
OS& operator()(OS& os)const {
return os << os.widen('b') << os.widen('o') << os.widen('b');
}
template<class OS>
operator OS&(*)(OS&)() const {
return [](OS& os)->OS&{ return bob_t{}(os); };
}
};
static const bob_t bob;
где bob
теперь объект, который можно использовать как манипулятор io.
1 это <<
перегрузка является функцией типа A->(A->A)->A
, По сути, вместо передачи X в f, мы передаем X и f в <<
который затем делает f(X)
, Чистый синтаксический сахар.
Дело в том, что std::endl
этот шаблон означает, что совершенная пересылка это немного больно из-за этой техники. Я в конечном итоге определить функцию без состояния endl_t
типы, с operator basic_ostream<CharT,Traits>&(*)(basic_ostream<CharT,Traits>&)()const
перегрузка, поэтому я могу иногда передавать набор перегрузки через совершенные прокси-серверы пересылки.
Тогда мы можем передать весь набор перегрузки f:(A->A)
в <<
и «следующий слой вниз» разрешит перегрузку.
http://en.cppreference.com/w/cpp/io/manip/endl говорит:
Определено в заголовке
<ostream>
template< class CharT, class Traits >
std::basic_ostream<CharT, Traits>& endl( std::basic_ostream<CharT, Traits>& os );
если я хочу написать свой собственный endl-манипулятор, какой код мне придется написать?
Если вы хотите создать его только для std::ostream
просто создайте функцию, которая принимает ссылку на std::ostream
и возвращает один. Если вы хотите сделать его универсальным, вы можете сделать его шаблонным, например, std::endl
,