0

I've overloaded std::ostream & operator<< many times for different data types in the past and never had a problem. However, for some reason, the following overload for Eigen::AlignedBox2i does not work with boost::log

std::ostream & operator<<( std::ostream & os, Eigen::AlignedBox2i const & rect )
{
  os << "foo";
  return os;
}

std::cout << Eigen::AlignedBox2i(); works just fine, but BOOST_LOG_TRIVIAL( debug ) << Eigen::AlignedBox2i(); results in a number of compiler errors, starting with:

D:\dev\ext\boost_1_80_0\boost/log/utility/formatting_ostream.hpp(929,16): error C2679: binary '<<': no operator found which takes a right-hand operand of type 'T' (or there is no acceptable conversion)

Any idea what is happening here?

DrPepperJo
  • 632
  • 1
  • 5
  • 19
  • 2
    `boost::log` is not a `std::ostream` – NathanOliver Nov 15 '22 at 20:18
  • You are right, but the doc says "[...] the stream will by default reuse the operators for std::basic_ostream", and I've been facilitating this successfully for years now. – DrPepperJo Nov 15 '22 at 20:43
  • https://stackoverflow.com/questions/32902904/properly-overload-operator-in-boost-log – DrPepperJo Nov 15 '22 at 20:43
  • I've done some more digging and it looks like it is designed to work with `std::ostream`. Did you write the overloaded operator or is it provided by `Eigen`? – NathanOliver Nov 15 '22 at 20:44
  • I wrote the overload and boiled it down to the minimal example I used in the question. Works fine with `std::cout` but not for `BOOST_LOG_TRIVIAL( debug )` – DrPepperJo Nov 15 '22 at 20:48
  • 2
    I beleive the issue is that `boost::log` relies on ADL to look up the function and if this operator is not in the Eigen namespace then it will never be found. – NathanOliver Nov 15 '22 at 20:50
  • You are right. Putting the function inside `namespace Eigen { ... }` does the trick. – DrPepperJo Nov 15 '22 at 21:05

1 Answers1

0

Your operator<< must be able to be found using ADL from Boost.Log namespace. For this, the operator must be defined in the namespace of one of its argument types. Given that defining new methods in namespace std is prohibited by the standard, you should move the operator to namespace Eigen.

Alternatively, you could define and use a manipulator type in your own namespace. This way you will not be affecting the Eigen library and remain compatible with it if some future Eigen version adds its own operator<<. For example:

class aligned_box_2i_manipulator
{
private:
    Eigen::AlignedBox2i const & m_rect;

public:
    explicit aligned_box_2i_manipulator(Eigen::AlignedBox2i const & rect) noexcept :
        m_rect(rect)
    {
    }

    friend std::ostream & operator<<( std::ostream & os, aligned_box_2i_manipulator manip )
    {
        os << "foo";
        return os;
    }
};

inline aligned_box_2i_manipulator to_stream(Eigen::AlignedBox2i const & rect) noexcept
{
    return aligned_box_2i_manipulator(rect);
}

std::cout << to_stream(Eigen::AlignedBox2i());
Andrey Semashev
  • 10,046
  • 1
  • 17
  • 27