Как использовать оператор выходного потока, определенный в заголовке
Я хотел бы иметь возможность добавлять содержимое любого std::vector<T>
в выходной поток. Я нашел этот код:
#ifndef DEBUG_H_
#define DEBUG_H_
#include <vector>
template < class T >
std::ostream& operator << (std::ostream& os, const std::vector<T>& v)
{
os << "[";
for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii)
{
os << " " << *ii;
}
os << "]";
return os;
}
#endif /* DEBUG_H_ */
и вставьте в заголовок Debug.h
, Как я могу использовать этот оператор в моем проекте?
РЕДАКТИРОВАТЬ: я убедился, что это работает в модульном тесте:
#include "Debug.h"
TEST_F(AuxGTest, testVectorDebug) {
std::vector<int> vec(10, 42);
std::cout << "vec: " << vec << std::endl;
}
Но использование его с лог-операторами log4cxx не работает:
#include <log4cxx>
#include "Debug.h"
namespace Foo {
class Bar {
void foo() {
std::vector<int> vec(10, 42);
DEBUG("vec: " << vec);
}
}
}
Это приводит к следующему сообщению компилятора:
/usr/local/Cellar/log4cxx/0.10.0/include/log4cxx/helpers/messagebuffer.h:190:47: error: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&'
2 ответа
Где вы пытаетесь его использовать? Как было объявлено, он находится в глобальном пространстве имен, поэтому ADL не найдет его, если T
это тип, определенный в глобальном пространстве имен. И он не будет найден при обычном поиске, если вы находитесь в пространстве имен, отличном от глобального пространства имен, и существует operator<<
в этом пространстве имен (что бы это скрыть). Он также не будет найден, если вызван в шаблоне, если какой-либо из аргументов является зависимым, так как поиск зависимого имени использует только ADL.
И, конечно, вы действительно не хотите этого делать, кроме как в игрушечных программах. Различное использование std::vector
потребуются разные форматы вывода; гораздо лучше обернутьstd::vector
в классе, и определить operator<<
для класса, для каждого отдельного семантического использования. (Для игрушечных программ вы можете определить оператора в пространстве имен std
, Неопределенное поведение, но так как никто другой никогда не увидит код или не будет его поддерживать, и это не конец света, если он не работает...)
РЕДАКТИРОВАТЬ:
Поскольку кажется, что вы используете это для какой-либо трассировки или отладки: это один из случаев, когда имеет смысл поддерживать унифицированный вывод для std::vector
, поскольку он используется для вывода внутреннего состояния. С другой стороны, в этом случае обычно ostream
быть завернутым, что-то вроде:
class Logger
{
std::ostream* myDest;
public:
Logger( std::ostream* dest )
: myDest( dest )
{
}
template <typename T>
Logger& operator<<( T const& value )
{
if ( myDest != NULL ) {
*myDest << value;
}
return *this;
}
};
Это позволяет конфигурировать протоколирование во время выполнения (плюс автоматическую вставку таких вещей, как __FILE__
а также __LINE__
, если вы используете макрос, чтобы получить экземпляр Logger
); твой макрос DEBUG
может быть что-то вроде:
#define DEBUG getLogger( TRACELEVEL_DEBUG, __FILE__, __LINE__ )
где getLogger
это глобальная функция, которая возвращает Logger
инициализируется с правильным ostream
(или нулевой указатель, если регистрация не активна для этого уровня). После этого вы можете добавить специальные функции, такие как:
template <typename T>
Logger& Logger::operator<<( std::vector<T> const& value )
{
if ( myDest != NULL ) {
// your code here...
}
return *this;
}
Поскольку одним из аргументов <<
Оператор будет экземпляром Logger
, ADL найдет оператора, независимо.
Есть похожий вопрос о пользовательских операторах с log4cxx. Я ответил на этот вопрос, порекомендовав поместить оператора в log4cxx::helpers
Пространство имен. Увидеть.