문제

I wanted to test a simple thing like the following:

#include <iostream>
#include <boost/variant.hpp>

template<typename T1,typename T2>
std::ostream& operator<<(std::ostream& os, const std::pair<T1,T2>& dt){
    os << dt.first << dt.second;
    return os;
}



int main(){

   boost::variant<int, std::pair<int,int>, bool> v;
   v = std::pair<int,int>(3,3);
   std::cout << v << std::endl;

}

This should actually work, because for normal types, like int, double and so on, it compiles. boost::variant has a printer vistor which it uses internally to output the content to the stream. Actually this fails to compile, but I do not really know the problem:

The codes fails here: in variant_io.hpp

template <typename OStream>
class printer
    : public boost::static_visitor<>
{
private: // representation

    OStream& out_;

public: // structors

    explicit printer(OStream& out)
        : out_( out )
    {
    }

public: // visitor interface

    template <typename T>
    void operator()(const T& operand) const
    {
        out_ << operand;  // HEEEEEEERRRRREE!!!!!!!!!!!!
    }

private:
    printer& operator=(const printer&);

};

With the message:

/usr/local/include/boost/variant/detail/variant_io.hpp|64|error: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&'

Does someone know what I did wrong, and why?

Thanks a lot!

도움이 되었습니까?

해결책

Most likely it's not finding your overload of operator <<, and then gets confused trying to match some other overload, leading to whatever message you're getting.

What you did wrong: You overloaded the stream operator in the global namespace instead of the namespace the right-hand-side class is defined in, so it's not found by ADL.

Trying to overload the stream operator for a standard class is a doomed exercise in the first place, unfortunately. You can't actually do that. I'm not sure if there is an explicit rule against it. However, if you place the operator in namespace std as you have to in order to make it properly findable by ADL, you violate the rule that you can't add your own stuff to namespace std except in very specific cases, this not being one of them.

The bottom line is that std::pair doesn't have a stream operator, and it's not possible to legally add a generic one that is useful. You can add one for a specific instantiation, if one of the parameters is a class you defined yourself; in this case the operator needs to be placed next to your own class.

다른 팁

Overloaded operator<< must be findable by argument dependent lookup. That means you have to put it in associated namespace of one of the arguments.

The first argument has only one associated namespace, std. The second also has only one associated namespace, std. However it is only permitted to overload symbols in std for user-defined types. Since std::pair<int, int> is not user-defined type, this is not allowed. However it is allowed for a structure or class you define yourself. Obviously in that case it is easier to place the overload to your namespace, not std.

That said if you put that overload in namespace std, it will actually work.

Also note, that boost::tuple does have operator<< (in separate header that you have to include, but it does), so you can use that instead.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top