c++c++17coutstringstreamostringstream

Create variable that contains a string and std::endl, that can be used in output streams to std::cout


Using c++17

I have a header file colors.hpp to help me with colored output to stdout:

#pragma once
#include <string>

namespace Color
{
    static const std::string yellow = "\u001b[33m";
    static const std::string green = "\u001b[32m";
    static const std::string red = "\u001b[31m";
    static const std::string end = "\u001b[0m";
}

I often use it like this:

std::cout << Color::green << "some green text " << Color::end << std::endl;

I almost always put std::endl immediately after Color::end. I'd like to be able to achieve the same result (newline + buffer flush), but use only one variable - something like Color::endl.

I've only been able to come up with solutions that are string, which as far as I understand, will include the \n character but will not also force the flush to stdout.

static const std::string endl = std::ostringstream(static_cast<std::ostringstream &&>(std::ostringstream() << Color::end << std::endl)).str();

If I remove the .str() from the code above, then I can't do: std::cout << Color::endl; because of

error: invalid operands to binary expression ('basic_ostream<char>' and 'const std::__1::basic_ostringstream<char>')

Solution

  • std::endl is a function (actually function template), not an object. That means, if you want to replicate it, you need a function as well.

    If you add this to Color:

    template< class CharT, class Traits >
    std::basic_ostream<CharT, Traits>& endl( std::basic_ostream<CharT, Traits>& os )
    { 
        return os << end << std::endl;
    }
    

    Then, when you use this:

    std::cout << Color::green << "some green text " << Color::endl;
    

    The Color::endl() function will get called, and then it can insert Color::end into the stream, and then std::endl to get the newline and flush behavior you want, as seen in this live example.