Question

I have stumbled upon an error for which I cannot grasp the reason.

I think it basically gets down to this error:

 error: no matching function for call to ‘std::basic_ostream<char>::operator<<(const std::basic_string<char>&)’

I looked into specification on www.cplusplus.com and indeed it says there is no definition for std::ostream::operator<< with std::string as an argument.

My question is, what happens when one writes std_ostream_instance << std_fancy_string;. I believe it is one of the most common invocations ( e.g. std::out << std::string("Hello world!") ) next to const char*.

The error originates from these lines:

template<typename T> 
void Log::_log(const T& msg)
{  _sink->operator<<( msg ); }

_sink is defied as std::ostream* There are some wrapping functions around but it breaks here.

I think I could work around by writing

template<> 
void Log::_log<std::string>(const std::string& msg) {
  _sink->operator<<( msg.c_str() );
}

since there is ostream& operator<< (ostream& out, const unsigned char* s ); defined by default.

I just see no reason why it is not guessed automatically since it clearly works in simple use like cout << any_std_string.

Not sure if this is relevant but I want to be able to pass down through my log functions anything than can be handled by std::ostream. I used explicit non-templated declarations but decided to move to template for log(const T& anything_to_log) to refacator it. It seemed plain stupid to have 5+ overloads. I get the error when I try compiling something like Log::log( std::string("test case") ).

It looks like something stupid-simple but I cannot get it on my own. Tried to google and search stack to no avail.

With regards, luk32.

PS. I checked the work-around and it works. Why it's not implicitly done ?

Was it helpful?

Solution

operator << overloads are not members of ostream. They are freestanding functions, for example

ostream& operator << ( ostream& out, const basic_string<T>& bs );

Try

template<typename T> 
void Log::_log(const T& msg)
{  *_sink << msg;  }

OTHER TIPS

The std::string version is not a member function, so can't be called as a member of _sink. Try it this way to pick up both member and non-member versions (in fact it is unlikely you will need the member versions at all anyway):

#include <iostream>
#include <string>

int main()
{
    std::ostream * os = &std::cout;
    std::string s = "Hello\n";

    // This will not work
    // os->operator<<(s);
    (*os) << s;

    return 0;
}

Or better yet would be to store _sink as a reference, and output exactly as you normally would to cout.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top