2

I wanted to create a method to add color to console output that would work in a similar way to std::left and std::setw(). I ended up with the code below, and it works exactly how I want it to. I understand how it works, but I would like some clarification on something.

Here is the code:

#include <iostream>
#include <Windows.h>

HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

enum class color { blue = FOREGROUND_BLUE, green, cyan, red, purple, yellow, white, bright = FOREGROUND_INTENSITY };

class coutColor {
public:

    WORD Color;

    coutColor(color colorvalue) : Color((WORD)colorvalue) {  }
    ~coutColor() { SetConsoleTextAttribute(hConsole, (WORD)7); }

};

std::ostream& operator<<(std::ostream& os, const coutColor& colorout) {

    SetConsoleTextAttribute(hConsole, colorout.Color);
    return os;

}

int main() {

    std::cout << coutColor(color::green) << "This text is green!\n";
    std::cout << color::red << "This text is red! " << 31 << "\n";

    return 0;
}

I understand how coutColor(color::green) works in the cout in main(), but why does just color::red by itself work as well?

I stumbled upon it by accident while testing different things.

How can it take the enum type color as an input, since it's not in the input parameters of the overloaded operator<<?

Why does it do the same thing as inputting coutColor(color::red)?

  • please one question per question. 2) no they are not the same. See here https://stackoverflow.com/questions/1711990/what-is-this-weird-colon-member-syntax-in-the-constructor and here https://en.cppreference.com/w/cpp/language/constructor – 463035818_is_not_an_ai Jan 31 '23 at 20:08
  • 6
    You have an `operator<<` that takes an `ostream&` and `const coutColor&` as arguments. You have a constructor that converts a `color` to a `coutColor`. Overload resolution is capable of performing implicit conversions like this. – Nathan Pierson Jan 31 '23 at 20:10
  • Alright. Thanks for the link. I removed the side question. @463035818_is_not_a_number – Markus Vaittinen Jan 31 '23 at 20:10
  • 1
    Also notable that your `operator<<` is a bit misleading. If I understand the gist of `SetConsoleTextAttribute` and `GetStdHandle` correctly, then your `operator<<` isn't really making any changes to its argument `os` at all. That is, if you had some other stream `foo` and did `foo << coutColor(color::green)`, this would have the effect of making `std::cout`, not `foo`, have green text. – Nathan Pierson Jan 31 '23 at 20:12
  • @NathanPierson: To be fair, OP did name his wrapper `coutColor`, so anyone thinking it operates on any stream other than `cout` is blind. Now, it might not even work on `cout` if the standard output is redirected... – Ben Voigt Jan 31 '23 at 20:15
  • But then why write an `operator<<` that takes another stream at all? – Nathan Pierson Jan 31 '23 at 20:16
  • @NathanPierson: You can't overload `operator<<` on the identity of its left operand. In order to have it work with `cout` (and you do want to use `<<` because that ensures the correct ordering), you get it syntactically fitting other undesired streams as well. (You also can't match `cout` specifically by type, e.g. `ostream_with_assign`, because chained `operator<<` loses the exact type) – Ben Voigt Jan 31 '23 at 20:47

1 Answers1

6

why does just color::red by itself work as well? ... How can it take the enum type color as an input, since it's not in the input parameters of the overloaded operator<<? Why does it do the same thing as inputting coutColor(color::red)?

It is because coutColor's constructor is not marked as explicit.

When the compiler is looking for a suitable overload of operator<< for the expression std::cout << color::red, it finds your overload in scope and sees that:

  1. coutColor is implicitly constructable from a color value

  2. the operator takes a coutColor object by const reference

So, the compiler is able to create a temporary coutColor object, passing the color value to its constructor, and then pass that object to the operator.

I have seen function(input) : var(input) {} before and I didn't know what it meant.

C++, What does the colon after a constructor mean?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770