Как использовать оператор выходного потока, определенный в заголовке

Я хотел бы иметь возможность добавлять содержимое любого 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 Пространство имен. Увидеть.

Другие вопросы по тегам