2

I’m a C++ newbie. I’ve tried to set up NetBeans and run a c++ program in my MacBook Air via virtual machine (UTM) lately. It works well in my company's Linux desktop, but somehow it just doesn’t work in my virtual Linux. The source code is the same in these two platforms, but they have different compilation result. One is fine, and the other shows the error message below.

error: no match for ‘operator<<’

I was wondering if it is due to the version mismatch or something similar of these two Linux environment. By the way, the author of this program has left the company, so I am doing my best to understand the his code. I’ve seen several posts here about this exactly the same issue, but it seems none of those solutions can work with my situation where this source code works well in one Linux while it doesn’t work in another one.

Below is the error message and relevant source codes. Could you please help me look into them? Thanks a lot!

Source code:

class logger
    {
      public:
        typedef std::ostringstream collector_stream_type;

      private:
        collector_stream_type _os;
        log_levels _messageLevel;

       public:
           logger(const logger & r) : _messageLevel(r._messageLevel)
              {
                   if ( do_log() ) _os << r._os; // this is where the error occurs.
               }
    }

Error / Warning message from NetBeans

In file included from

  • error: no match for ‘operator<<’ (operand types are ‘MySoftware::log::logger::collector_stream_type’ {aka ‘std::__cxx11::basic_ostringstream’} and ‘const collector_stream_type’ {aka ‘const std::__cxx11::basic_ostringstream’})
  • note: cannot convert ‘r.MySoftware::log::logger::_os’ (type ‘const collector_stream_type’ {aka ‘const std::__cxx11::basic_ostringstream’}) to type ‘const std::error_code&’
  • note: ‘const collector_stream_type’ {aka ‘const std::__cxx11::basic_ostringstream’} is not derived from ‘const std::complex<_Tp>’
  • note: cannot convert ‘((MySoftware::log::logger*)this)->MySoftware::log::logger::_os’ (type ‘MySoftware::log::logger::collector_stream_type’ {aka ‘std::__cxx11::basic_ostringstream’}) to type ‘std::byte’
  • note: candidate: ‘operator<<(int, int)’ (built-in)
  • note: ‘const collector_stream_type’ {aka ‘const std::__cxx11::basic_ostringstream’} is not derived from ‘const std::__shared_ptr<_Tp, _Lp>’
  • note: deduced conflicting types for parameter ‘_CharT’ (‘char’ and ‘std::__cxx11::basic_ostringstream’...
Zureas
  • 53
  • 5
  • 2
    In `_os << r._os` both sides of the `<<` are streams. There is no predefined operator for that, so don't know what is intended. The error messages are just the compiler trying to be "nice" by showing the closest matches (and why none of them is usable here). – BoP Jun 25 '23 at 20:21
  • @BoP, thanks a lot! Then how would you think about that NetBeans in my company's desktop doesn't show the error message while the Linux in my virtual machine shows it? Does it mean somehow this `_os << r._os` works? If so, would it be because the c++ or gcc version in my virtual machine is not new enough? Thanks. – Zureas Jun 25 '23 at 20:30
  • 1
    The code `_os << r._os` can of course work, if someone writes an overload for `<<`. There just isn't anything like that in the C++ standard. That rules out different compiler versions, but not different 3rd party libraries. – BoP Jun 25 '23 at 20:33
  • @BoP thanks a lot again!! This really helps. So maybe some 3rd party libraries are not correctly imported / included in my Linux virtual machine? I will look into it. Thank you so much for your quick reply. – Zureas Jun 25 '23 at 20:35

1 Answers1

3

This was probably always wrong (assuming there isn't some user-defined operator<< overload candidate hiding somewhere in your code).

There is and never has been any overload of operator<< in the standard library that would take two std::ostringstream or related types as parameters.

Instead before C++11 the chosen overload would be

std::basic_ostream::operator<<(const void*)

because the std::basic_ios base class of the right-hand std::ostringstream of _os << r._os had a conversion function to void* that could implicitly convert r._os to void*. The result would be a null pointer if the stream is in a fail() state and any other pointer value otherwise.

The result is that _os << r._os will write to _os a numeric representation of a null pointer if r._os is in a fail() state and any other numeric representation of a pointer value otherwise.

That doesn't seem intended.

Since C++11 the conversion function has been changed to convert to bool instead and has been made explicit so that it isn't viable any more for an implicit conversion to use the operator<<(const void*) overload. The change is meant to prevent exactly such mistakes.


Side note: The error messages are not from Netbeans. Netbeans is your IDE. The error messages are from your compiler, which seems to be GCC according to what you wrote.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • Hello, first of all, I want to say thank you for your great help! But honestly, I don't really get it, because I'm new to C++. I was wondering if you can give my some advices about self-learning those concepts you mentioned in this answer? It looks like I have a lot to learn. (I only have some python experience) – Zureas Jun 25 '23 at 20:42
  • 1
    @KaoEthan Any [introductory book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) to the language will probably explain what these classes do, at least a rough overview. The details are very complex. – user17732522 Jun 25 '23 at 20:47
  • 1
    @KaoEthan Then you can use https://en.cppreference.com/w/ for a (dense) reference of the language and standard library. For example the relevant pages here are https://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt with the `const void*` overload for `<<` and https://en.cppreference.com/w/cpp/io/basic_ios/operator_bool with the conversion function and a link to the standard defect report [LWG 468](https://cplusplus.github.io/LWG/issue468) at the bottom. – user17732522 Jun 25 '23 at 20:47
  • 2
    *I don't really get it* -- [Start out with a smaller program](https://godbolt.org/z/fM83c4hs7). Now try and get that program to compile cleanly. – PaulMcKenzie Jun 25 '23 at 20:48
  • Thank you @user17732522 for your side note. I just found out that the compiler for C is gcc, while the compiler for c++ is g++. Not quite sure if it is relevant. – Zureas Jun 25 '23 at 20:49
  • Wow @PaulMcKenzie, that page is really good. Thanks for sharing this. I will start working on it! Yes, you're right. I will start out with a smaller program.. – Zureas Jun 25 '23 at 20:50
  • 1
    @KaoEthan You'll need to understand what the original author of the code intended the expression `_os << r._os` to do. My guess is to write the whole right-hand stream to the left-hand side stream. Then implement that properly, e.g. by reading from the right-hand side into a `std::string` first and then writing the string to the left-hand side. The underlying string buffer can also be used for that directly, see e.g. the `rdbuf` member function. But maybe the behavior of writing a pointer value representing the stream state was also intended, in which case you'll have to reimplement that... – user17732522 Jun 25 '23 at 20:50
  • @user17732522, your replies are amazing. Thanks for those reference information! I will look into the cppreference and find an introductory book for this. Your understanding makes a lot sense. I didn't really know the original author's intention for this, but I will start thinking about it. Thank you very much. – Zureas Jun 25 '23 at 20:53
  • 1
    @KaoEthan -- [Here is a quick and dirty fix that works, regardless of compiler](https://godbolt.org/z/3bjY7rzv4). You can call the `str()` member function to concatenate the incoming stream onto the outgoing stream. – PaulMcKenzie Jun 25 '23 at 20:56
  • By the way, how would you guys explain that this code can work on my another Linux desktop? Maybe different 3rd party libraries are used? – Zureas Jun 26 '23 at 08:10
  • @Zureas You used a compiler that is set either explicitly or by default to C++98 or C++03 mode, so probably an older compiler. As I explained in my answer the line _was_ valid in these C++ versions. However, I expect that the _behavior_ that the line had in these versions is not what the author intended. That's what the majority of my answer is about. – user17732522 Jun 26 '23 at 13:35
  • Hi @user17732522, thank you very much for your great help! I will look into it and let you know once I make any progress! Thank you. – Zureas Jun 27 '23 at 19:38