0

I would like to be able to append the content of any std::vector<T> to an output stream. I've found this code:

#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_ */

and put in in a header Debug.h. How can I use this operator troughout my project?

EDIT: I have verified that this works in a unit test:

#include "Debug.h"

TEST_F(AuxGTest, testVectorDebug) {
    std::vector<int> vec(10, 42);
    std::cout << "vec: " << vec << std::endl;
}

But using it with log statements of log4cxx does not work:

#include <log4cxx>
#include "Debug.h"

namespace Foo {
    class Bar { 
        void foo() {
            std::vector<int> vec(10, 42);
            DEBUG("vec: " << vec);
        }

    }

}

This results in the following compiler message:

/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>&&'
clstaudt
  • 21,436
  • 45
  • 156
  • 239
  • possible duplicate of [Overloading operator<<: cannot bind lvalue to ‘std::basic\_ostream&&’](http://stackoverflow.com/questions/10651161/overloading-operator-cannot-bind-lvalue-to-stdbasic-ostreamchar) – Rapptz Apr 23 '13 at 16:02
  • 1
    Mostly you just need to include the header in the source file where you want to use the operator, then just do something like `std::cerr << your_vector;` – Jerry Coffin Apr 23 '13 at 16:06
  • @JerryCoffin Try it if the code is in a template, and `T` is one of the basic types, like `int`. (It might still work with MSVC, but it won't with a compiler which implements C++98 or above.) – James Kanze Apr 23 '13 at 16:08
  • @JamesKanze: I interpreted the question as a simple one of how to deploy this code for use in the project, not the rather more complex one of how to actually make the code work under any but the most trivial of conditions (but especially after rereading the question, I'll openly admit that could have been a mistake). – Jerry Coffin Apr 23 '13 at 16:17

2 Answers2

3

Where are you trying to use it? As declared, it's in the global namespace, so it won't be found by ADL unless T is a type defined in the global namespace. And it won't be found by normal lookup if you're in a namespace other than global namespace, and there is an operator<< in that namespace (which would hide it). It also won't be found if invoked in a template, if any of the arguments are dependent, since dependent name lookup only uses ADL.

And of course, you really don't want to do this except in toy programs. Different uses of std::vector will require different output formats; it's far better to wrap the std::vector in a class, and define the operator<< for the class, for each different semantic use. (For toy programs, you can define the operator in namespace std. Undefined behavior, but since no one else will ever see the code, or have to maintain it, and it's not the end of the world if it doesn't work...)

EDIT:

Since it seems that you're using this for some sort of tracing or debugging: this is one case where it does make sense to support a unified output for std::vector, since it is used to output internal state. On the other hand, it is usual in this case for the ostream to be wrapped, something like:

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;
    }
};

This allows runtime configuration of the logging (plus automatic insertion of things like __FILE__ and __LINE__, if you use a macro to get the instance of Logger); your macro DEBUG might be something like:

#define DEBUG getLogger( TRACELEVEL_DEBUG, __FILE__, __LINE__ )

where getLogger is a global function which returns a Logger initialized with the correct ostream (or a null pointer, if logging isn't active for that level). Once you do this, you can add special functions, like:

template <typename T>
Logger& Logger::operator<<( std::vector<T> const& value )
{
    if ( myDest != NULL ) {
        //  your code here...
    }
    return *this;
}

Since one of the arguments the the << operator will be an instance of Logger, ADL will find the operator, regardless.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • I tried to make clear where I use it with a mock example. The actual code would be quite verbose. – clstaudt Apr 23 '13 at 16:16
  • Can you point me to a code example where a `std::vector` is wrapped and an operator `<<` is added? – clstaudt Apr 23 '13 at 16:23
  • @cls Not off hand, but it doesn't seem like a difficult concept. You define a class which contains an `std::vector` (giving it an interface appropriate for its role in your application), and you write an `operator<<` for that class. – James Kanze Apr 23 '13 at 16:30
  • @cls Re your example: what is in `"log4cxx"`? In particular, does it do anything which might result in the compiler needing ADL to find your `operator<<`? – James Kanze Apr 23 '13 at 16:41
  • @cls Debugging output may be an exception to my statement that you don't want a global output for `vector`. I've edited my answer to show how I handle the issue. – James Kanze Apr 23 '13 at 16:52
  • What does ADL stand for? log4cxx is an Apache library, which provides the underlying logging macros. `DEBUG` is my macro for for `LOG4CXX_DEBUG(log4cxx::Logger::getRootLogger(), MESSAGE)`. I would like to stick with that, not define another logger. – clstaudt Apr 23 '13 at 16:54
  • @cls ADL is argument dependent lookup. And I don't know the library, so I cannot say whether it does something which causes outputting vectors to require ADL to find the `<<` (but it looks like it). – James Kanze Apr 23 '13 at 17:09
0

There is a similar question about user-defined operators with log4cxx. I answered that question by recommending placing the operator in the log4cxx::helpers namespace. See .

Community
  • 1
  • 1
Phil
  • 5,822
  • 2
  • 31
  • 60