Ответ 1
Qt использует метод, подобный @Evan. См. версию qdebug.h для деталей реализации, но они передают все в базовый текстовый поток, а затем очищают поток и конец, строка об уничтожении временного объекта QDebug, возвращаемого qDebug().
Я пытаюсь реализовать свой собственный поток отладки-вывода в стиле qDebug()
, это в основном то, что я имею до сих пор:
struct debug
{
#if defined(DEBUG)
template<typename T>
std::ostream& operator<<(T const& a) const
{
std::cout << a;
return std::cout;
}
#else
template<typename T>
debug const& operator<<(T const&) const
{
return *this;
}
/* must handle manipulators (endl) separately:
* manipulators are functions that take a stream& as argument and return a
* stream&
*/
debug const& operator<<(std::ostream& (*manip)(std::ostream&)) const
{
// do nothing with the manipulator
return *this;
}
#endif
};
Типичное использование:
debug() << "stuff" << "more stuff" << std::endl;
Но я бы не хотел добавлять std::endl;
Мой вопрос в основном, как я могу сказать, когда тип возвращаемого значения operator<<
не будет использоваться другим operator<<
(и, следовательно, добавить endl
)?
Единственный способ, которым я могу придумать для достижения чего-либо подобного, - это создать список вещей для печати, связанных с каждым временным объектом, созданным qDebug()
, а затем распечатать все вместе с завершающим переводом строки (и я могу делать умные вещи как вставка пробелов) в ~debug()
, но, очевидно, это не идеально, так как у меня нет гарантии, что временный объект будет уничтожен до конца области (или я?).
Qt использует метод, подобный @Evan. См. версию qdebug.h для деталей реализации, но они передают все в базовый текстовый поток, а затем очищают поток и конец, строка об уничтожении временного объекта QDebug, возвращаемого qDebug().
Что-то вроде этого будет делать:
struct debug {
debug() {
}
~debug() {
std::cerr << m_SS.str() << std::endl;
}
public:
// accepts just about anything
template<class T>
debug &operator<<(const T &x) {
m_SS << x;
return *this;
}
private:
std::ostringstream m_SS;
};
Что должно позволить вам делать такие вещи:
debug() << "hello world";
Я использовал шаблон, подобный этому, в сочетании с блокировкой, чтобы обеспечить поток, такой как система ведения журнала, которая может гарантировать, что записи журнала записываются атомарно.
ПРИМЕЧАНИЕ: непроверенный код, но должен работать: -)
Когда вы пишете, что это типичное использование:
debug() << "stuff" << "more stuff" << std::endl;
Вы определенно планируете создавать объект отладки каждый раз, когда используете его? Если это так, вы должны иметь возможность получить нужное поведение, если деструктор отладки добавит новую строку:
~debug()
{
*this << std::endl;
... the rest of your destructor ...
}
Это означает, что вы не можете сделать что-то вроде этого:
// this won't output "line1" and "line2" on separate lines
debug d;
d << "line1";
d << "line2";
Вставка потока (<<
) и извлечения (>>
) должны быть нечленами.
Мой вопрос в основном, как я могу указать, когда тип возврата Оператор < < не будет использоваться другой оператор < (и так добавить епсИ)?
Вы не можете. Создайте функцию-член, чтобы добавить это или добавить endl
после завершения этих цепочечных вызовов. Хорошо документируйте свой класс, чтобы клиенты знали, как его использовать. Это лучший выбор.