4

I am trying out the following C++ class for using the stream operator << to log contents from this answer:

class Log
{
public:
    Log()
        : m_filename( "dafault.log" )
    {}

    // if you wanna give other names eventually...
    Log( const std::string & p_filename )
        : m_filename( p_filename )
    {}

    virtual ~Log()
    {
        // implement  your writeToFile() with std::ofstream 
        writeToFile( m_filename, m_stream, true );
    } 

    template< typename T >
    Log & operator<<( const T & p_value )
    {
        m_stream << p_value;
        return *this;
    }

private:
    std::string         m_filename;
    std::ostringstream  m_stream;
};

This works for many cases. However, it fails to compile when trying to stream std::endl,

Log( "/tmp/my.log" ) << 1 << std::endl;

, giving an error like this:

/usr/include/c++/7/string_view:558:5: note:   template argument deduction/substitution failed:
My.cpp:375:36: note:   'Log' is not derived from 'std::basic_ostream<_CharT, _Traits>'
  Log( "/tmp/my.log" ) << 1 << std::endl;
                                    ^~~~

How to make it work with std:endl as well?

Hudson
  • 312
  • 2
  • 18
thor
  • 21,418
  • 31
  • 87
  • 173
  • 6
    You need something like `operator<<` overload (12) [here](http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt). `std::endl` is a function template, and parameter deduction for it would only work if it's used just so. – Igor Tandetnik Nov 22 '17 at 05:58
  • Take a look at one my answers. Hopefully it's useful. https://stackoverflow.com/a/24413884/434551. – R Sahu Nov 22 '17 at 06:02
  • @IgorTandetnik Even though I know this error could be fixed by adding an overload, I really am wondering why `const T&` is not matched by `std::endl`. I even tried a more permissive one [here](https://ideone.com/k9185F) and it doesn't match either. The compiler says `couldn't deduce template parameter ‘T’`. Why? Shouldn't `T` be able to match anything in the world? – Telokis Nov 22 '17 at 10:26
  • 1
    @Telokis Not anything in the world. `T` could be deduced from objects or functions - things that have type. But `std::endl` is not a function, it's a function template - an infinite family of functions, all of different types. Before its type can become known and deduced for `T`, its own template parameters need to be deduced, or explicitly specified. Thus, `log << std::endl>` would likely work. – Igor Tandetnik Nov 22 '17 at 13:44
  • @IgorTandetnik Ok, I finally get it after all these years wondering! Thank you for that extra precision. I totally missed the fact that it's not "just" a function. – Telokis Nov 22 '17 at 13:45
  • Ordinary it's a bad idie to make operator<< as a membar. – Alexandr Nov 23 '17 at 05:50
  • I tried to use library template, but i can't to make it work. So from library: flush(log.m_stream.put(log.m_stream.widen('\n'))); - it's identicaly what do endl; – Alexandr Nov 24 '17 at 12:04
  • I personally do not like to use std::endl but rather '\n' for a new line. std::endl flushes the output buffer. – Hudson Mar 12 '23 at 01:15

0 Answers0