Я искренне не понимаю разницы. Вот несколько примеров:
Использование std::cout
#include <iostream>
#include <list>
using namespace std;
void print(std::list<std::string> const &list)
{
for (auto const &i: list)
{
cout << i << endl;
}
}
int main()
{
std::list<std::string> list = { "blue", "red", "green" };
print(list);
return 0;
}
Следующий вывод:
blue
red
green
Для второго примера я также буду использовать std::cout:
#include <iostream>
#include <list>
using namespace std;
int main()
{
std::list<std::string> list = { "blue", "red", "green" };
cout << list << endl;
return 0;
}
Однако я получаю следующую ошибку:
error: no type named ‘type’ in ‘struct std::enable_if<false, std::basic_ostream<char>&>’
Итак, я использую перегрузку оператора следующим образом:
#include <iostream>
#include <list>
using namespace std;
std::ostream &operator<<(std::ostream &os, std::list<std::string> &list)
{
os << list << endl;
return os;
}
int main()
{
std::list<std::string> list = { "blue", "red", "green" };
cout << list << endl;
return 0;
}
Сначала это компилируется нормально, но когда я его запускаю, я получаю ошибку времени выполнения:
Segmentation fault (core dumped)
Почему мы не можем просто cout
все из списка, и почему мы должны использовать цикл, чтобы напечатать каждый элемент внутри списка?
Кроме того, как мне решить проблему второго примера? Я заметил, что когда я отлаживаю свой код, он застревает внутри перегрузки оператора, которая, как я полагаю, вызывает сбой.
Заранее спасибо!
В первом примере у вас есть правильный код для печати каждого элемента списка. Во втором фрагменте кода вы ожидаете, что
os << list << endl;
волшебным образом сделает это. Но на самом деле это вызывает перегруженныйoperator<<
, который снова вызывает сам себя, который снова вызывает себя, который снова вызывает себя ... до тех пор, пока ваш стек не переполнится.Я только что добавил новый пример между
std::cout
и перегрузкой оператора, если кого-то смущает, почему он упомянул о втором фрагменте кода, являющемся перегрузкой оператора.По умолчанию стандартные контейнеры (например,
std::list
) не имеют операторов потоковой передачи, поэтому, если они вам нужны, вам необходимо их предоставить — отсюда и ошибка компиляции во втором случае. Это ограничение означает, что контейнер можно использовать для хранения набора элементов, у которых нет собственных операторов потоковой передачи. Ваш третий пример бесконечно рекурсивен (вашoperator<<()
безоговорочно вызывает себя в оператореos << list << endl
, следовательно (практически) либо ошибка времени выполнения (из-за исчерпания стека), либо бесконечный цикл (если компилятор переводит рекурсивные вызовы в итерацию).