Как работает 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;
Мой вопрос в основном, как я могу узнать, когда возвращаемый тип оператора<< не будет использоваться другим оператором << (и, таким образом, добавить endl)?
Единственный способ, которым я могу придумать для достижения чего-либо подобного, - это создать список вещей для печати, связанных с каждым временным объектом, созданным debug(), а затем распечатать все вместе с завершающим переводом строки (и я мог бы делать умные вещи как вставка пробелов) в ~ debug(), но, очевидно, это не идеально, так как у меня нет гарантии, что временный объект будет уничтожен до конца области (или я?).
4 ответа
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)?
Ты не можешь. Создайте функцию-член, чтобы специально добавить это или добавить endl
как только эти цепные вызовы сделаны с. Хорошо документируйте свой класс, чтобы клиенты знали, как им пользоваться. Это ваша лучшая ставка.