Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

logging pointer to struct #84

Closed
fantastory opened this issue May 14, 2019 · 6 comments

Comments

@fantastory
Copy link

commented May 14, 2019

What I want to do is:

struct A {
  int a;
};

A *theA = getPointerToA();

//ostream operator defined externally since I do not own struct A code
std::ostream &operator<<(std::ostream& stream, const A*  item) {
  if (item) stream<<item->a;
  else stream<<"null A"; 
  return stream; 
}

BOOST_LOG_TRIVIAL(info) << theA;

But as we look into
lib\native\include\boost\log\utility\formatting_ostream.hpp
there is an
basic_formatting_ostream& operator<< (const void* value);
defined which takes precedence over the one defined by me (visual studio 2017)

I can solve it by logging reference instead of pointer, but being it a diagnostic function I would like to check for nullptr.

std::ostream &operator<<(std::ostream& stream, const A&  item) {
  if (&item) stream<<item->a;
  else stream<<"null A"; 
  return stream; 
}
BOOST_LOG_TRIVIAL(info) << *theA;

This actually works on visual studio, but it breaks non null reference, which is not allowed on clang.

Finaly I can declare operator<< as a template

template<class OST> std::enable_if_t<std::is_same_v<char, typename OST::char_type>, OST&> operator<<(OST& stream, const A*      item) 
{
  if (item) stream<<item->a;
  else stream<<"null A"; 
  return stream; 
}

It works well, but stream operators are used everywhere in a projects and it greatly lengthes compilation.

Would it be possible to remove
basic_formatting_ostream& operator<< (const void* value);
from
lib\native\include\boost\log\utility\formatting_ostream.hpp
?

@Lastique

This comment has been minimized.

Copy link
Member

commented May 14, 2019

Would it be possible to remove basic_formatting_ostream& operator<< (const void* value);?

That overload reflects the similar overload in std::basic_ostream, see [ostream.inserters.arithmetic]. Given that basic_formatting_ostream is supposed to mirror std::basic_ostream, I can't just remove the overload. But I think I could try to forward the original pointer type to the std::basic_ostream inserter so that your overload gets picked up instead of the one for const void*.

In the meantime, you can work around the problem by adding an overload like this:

template< typename Char, typename Traits, typename Allocator >
basic_formatting_ostream< Char, Traits, Allocator >& operator<< (
    basic_formatting_ostream< Char, Traits, Allocator >& stream, const A* value)
{
    stream.stream() << value;
    return stream;
}

It is more preferable than the const void* overload and should be picked by the compiler. It will reuse your existing overload for std::ostream.

@fantastory

This comment has been minimized.

Copy link
Author

commented May 15, 2019

Declaring:

#include "pch.h"
#include <boost/test/unit_test.hpp>
#include <boost/log/trivial.hpp>

struct LoggerTestStructA {
    int a;
};
std::ostream& operator<<(std::ostream& stream, const LoggerTestStructA *item) {
    stream << __FUNCTION__;
    return stream;
}

template< typename Traits, typename Allocator >
boost::log::basic_formatting_ostream< char, Traits, Allocator >& operator<< (
        boost::log::basic_formatting_ostream< char, Traits, Allocator >& stream, const LoggerTestStructA* value)
{
    stream.stream() << __FUNCTION__;
    return stream;
}

BOOST_AUTO_TEST_CASE(LoggerTest) {
    LoggerTestStructA *itemA = nullptr;
    void *voidPointer = nullptr;
    BOOST_LOG_TRIVIAL(info) << "initializing";
    BOOST_LOG_TRIVIAL(info) << "itemA:"<< itemA;
    BOOST_LOG_TRIVIAL(info) << "voidPointer:" << voidPointer;
}

Does not compile with:
error C2666: 'boost::log::v2s_mt_nt6::basic_record_ostream::operator <<': 3 overloads have similar conversions ...

@fantastory

This comment has been minimized.

Copy link
Author

commented May 15, 2019

I wondered if
basic_formatting_ostream& operator<< (const void* value);
is really needed, since without it compiler could use operator<<(void *) from std.
But as I removed it the code uses basic_formatting_ostream& operator<< (const bool value);
Instead of my operator.

@Lastique

This comment has been minimized.

Copy link
Member

commented May 15, 2019

Does not compile with:
error C2666: 'boost::log::v2s_mt_nt6::basic_record_ostream::operator <<': 3 overloads have similar conversions ...

Right, another overload is needed for basic_record_ostream:

boost::log::record_ostream& operator<< (
        boost::log::record_ostream& stream, const LoggerTestStructA* value)
{
    stream.stream() << __FUNCTION__;
    return stream;
}

Actually, depending on what formatters you set, you may not need the overload for basic_formatting_ostream and the one for record_ostream may be enough.

I wondered if
basic_formatting_ostream& operator<< (const void* value);
is really needed, since without it compiler could use operator<<(void *) from std.

basic_formatting_ostream does not derive from std::basic_ostream, it has to forward the call to the operator<< for std::basic_ostream.

@fantastory

This comment has been minimized.

Copy link
Author

commented May 15, 2019

:) yeah i just figured it out
basic_record_ostream is enaugh for me. I am clearing my example.

@fantastory

This comment has been minimized.

Copy link
Author

commented May 15, 2019

Code below is working for me. Great thanks :)
And it allows to remove all templates - actually I know I am not using wchar_t.

#include "pch.h"
#include <boost/log/trivial.hpp>
#include <boost/test/unit_test.hpp>
#include <sstream>

struct LoggerTestA {
    int a;
};

std::ostream& operator<<(std::ostream& stream, const LoggerTestA *item) {
    stream << __func__;
    return stream;
}

typedef boost::log::basic_record_ostream<char> BoostLogRecordStream;
BoostLogRecordStream& operator<< (
    BoostLogRecordStream& stream, const LoggerTestA* value)
{
    stream.stream() << __func__ << ":passingto: "<<value;
    return stream;
}

BOOST_AUTO_TEST_CASE(LoggerTest) {
    LoggerTestA *item = nullptr;
    BOOST_LOG_TRIVIAL(info) << "initializing";
    BOOST_LOG_TRIVIAL(info) << "item:"<<item;
    BOOST_LOG_TRIVIAL(info) << item;

    std::stringstream sstream;
    sstream << item;
    BOOST_LOG_TRIVIAL(info) << "stream:"<<sstream.str();
}

@Lastique Lastique closed this in d66ab73 May 25, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.