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

BOOST_LOG_TRIVIAL cannot find overloaded operator<<() when it's declared in global scope #207

Closed
vehlwn opened this issue Apr 3, 2023 · 2 comments

Comments

@vehlwn
Copy link

vehlwn commented Apr 3, 2023

BOOST_LOG_TRIVIAL and BOOST_LOG behavior seems not to be equivalent to std::cout and other standard iostreams. Here is an example:

main.cpp:

#include <iostream>

#include <boost/log/sources/logger.hpp>
#include <boost/log/trivial.hpp>

namespace test {
struct A {};
} // namespace test

std::ostream &operator<<(std::ostream &os, const test::A &) {
  os << "A";
  return os;
}

int main() {
  test::A a;
  std::clog << a << std::endl;

  namespace src = boost::log::sources;
  src::logger lg;
  BOOST_LOG_TRIVIAL(info) << a;
  BOOST_LOG(lg) << a;
}

meson.build:

project('boost-log-mre', ['cpp'], default_options: ['cpp_std=c++17'])
boost_dep = dependency('boost', modules: ['log'], include_type: 'system')
executable( 'a', ['main.cpp'], dependencies: [boost_dep])

build:

$ mkdir build && cd build
$ meson setup --buildtype debug
$ meson compile

Arch Linux, boost 1.81.0-3, gcc version 12.2.1 20230201, clang version 15.0.7

It fails to compile on GCC and Clang at BOOST_LOG_TRIVIAL and BOOST_LOG lines due to missing overload:

/usr/include/boost/log/utility/formatting_ostream.hpp:929:19: error: no match for ‘operator<<’ (operand types are ‘boost::log::v2_mt_posix::basic_formatting_ostream::ostream_type’ {aka ‘std::basic_ostream’} and ‘test::A’)
929 | strm.stream() << value;

But when I move definition of operator<<() into namespace test, it magically fixes itself. std::clog line works well in both cases. Is this intentional behavior or a bug in boost::log? I've stumbled upon this problem when tried to output Poco::Net::SocketAddress into BOOST_LOG_TRIVIAL because it declares it's overloaded operator<<() in a global scope and not in a scope of SocketAddress.

https://github.com/pocoproject/poco/blob/1211613642269b7d53bea58b02de7fcd25ece3b9/Net/include/Poco/Net/SocketAddress.h#L304

@Lastique
Copy link
Member

Lastique commented Apr 3, 2023

This behavior is intended and by design. The operator<< for the class A must be findable using ADL, meaning it should probably be defined in namespace test.

The fact that it works with std::clog is because the operator is visible from the context of the streaming expression. With Boost.Log, the operator<< you're calling from the streaming expression is not the one you declared in the global namespace but one of the forwarding operators provided by Boost.Log in its namespace. These forwarding operators shadow the operator<< in the global namespace, and ADL does not find it either as it is not in any of the associated namespaces.

The code in your example is rather fragile because it can easily break due to the operator being shadowed by other operators defined for other types. Here's an example.

@Lastique Lastique closed this as completed Apr 3, 2023
@vehlwn
Copy link
Author

vehlwn commented Apr 4, 2023

Thanks for the explanation! Then I'll create issue in the Poco repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants