DEV Community

DHDucky
DHDucky

Posted on • Edited on

Did I learn it? #1

Program-defined types: Enumeration (Part 1)

Unscoped enumerations

Although I am no professional, I have a fundamental understanding of the typical data types of C++: int, double, string and whatnot. But after a while, those started to get repetitive and boring. And that's when our today protagonist comes in. With an example, you'll get exactly what I'm talking about.

// Define a new unscoped enumeration named Family
enum Family
{
    // Here are the enumerators
    // These symbolic constants define all the possible values this type can hold
    // Each enumerator is separated by a comma, not a semicolon
    dad,
    mom,
    uglysis, // trailing comma optional but recommended
}; // the enum definition must end with a semicolon

int main()
{   // Define a few variables of enumerated type Color
    Family inTheKitchen { mom };   // mom is in the kitchen
    Family watching TV { dad }; // dad is watching TV
    Family ugly { uglysis };    // uglysis is ugly

    Family noChance { prettysis }; // error: prettysis is not an enumerator of Family

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Without needing any prior knowledge, you can understand the program easily. To create such programs, some knowledge are required, of course. But you can imagine, at least that's what I would imagine, what programmers do. By simplying the codes using unclosed enumerations, with minimal usage of comments, you and your collegues (if you ever graduate and make it) are gonna have a better time coding.

And something more interesting is that each enumerator are assigned a value that's continous from the previous enumerator, with 0 as the first if no assigning or done. Also, if two enumerators are assigned the same number, they're interchangeable, though not recommended.

#include <iostream>

enum Color
{
    black, // assigned 0
    red, // assigned 1
    blue = 5, // assigned 5
    green, // assigned 6
    white, // assigned 7
    cyan = -2, // assigned -2
    yellow, // assigned -1
    magenta, // assigned 0
};

int main()
{
    Color shirt{ blue }; // This actually stores the integral value 5

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Even though not learning everything about it yet, I have made an attempt to try do what I know and do input/output. Let's just say their are better ways ... but it's simple to understand. You can try to do it yourself by defining an enumerated type with the name Color but this is my attempt.

#include <iostream>
#include <string>

using namespace std;

enum Color
{
    red,
    green,
    blue,
};

int main()
{
    Color shirt;
    string shirtInput;
    cin >> shirtInput;
    if (shirtInput == "blue") shirt = blue;
    if (shirtInput == "red") shirt = red;
    if (shirtInput == "green") shirt = green;
    if (shirt == blue) 
        cout << "Your shirt is blue!";
    else
        cout << "Your shirt is not blue!";

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

And next is an attempt of pure magic to my eyes:

#include <iostream>

enum Color
{
    black,
    red,
    blue,
};

// Teach operator<< how to print a Color
// Consider this magic for now since we haven't explained any of the concepts it uses yet
// std::ostream is the type of std::cout
// The return type and parameter type are references (to prevent copies from being made)!
std::ostream& operator<<(std::ostream& out, Color color)
{
    switch (color)
    {
    case black: return out << "black";
    case red:   return out << "red";
    case blue:  return out << "blue";
    default:    return out << "???";
    }
}

int main()
{
    Color shirt{ blue };
    std::cout << "Your shirt is " << shirt; // **it works!**

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Any Dumbledores out there that can give me some insights before I learn it from Alex (the creator of the website I'm referencing), then please, you are welcomed and I give you my thanks.

REFERENCE
Chapter 10.1-10.2

Top comments (2)

Collapse
 
moshikoi profile image
MoshiKoi

Your code looks mostly fine; though usually you would ALLCAPS unscoped enumerations by convention.
However, unscoped enumerations have pretty much been superceded by scoped enumerations. For instance:

enum class Color { Red, Green, Blue };
Enter fullscreen mode Exit fullscreen mode

This is due to scoping and strong typing. Unscoped enumerations are unscoped, meaning you end polluting the namespace. (This is also why using namespace std; is also not recommended.) In addition, they are implicitly convertable to their underlying type, which can hide bugs.1 Take for instance your above code, but without the operator overload.

#include <iostream>

enum Color
{
    black,
    red,
    blue,
};

int main()
{
    Color shirt{ blue };
    std::cout << "Your shirt is " << shirt; // prints "Your shirt is 2"

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

This is probably not what you want. With a scoped enumeration, the equivelant code would cause a compilation error.

#include <iostream>

enum class Color
{
    black,
    red,
    blue,
};

int main()
{
    Color shirt = Color::blue;
    std::cout << "Your shirt is " << shirt; // error: invalid operands to binary expression ('basic_ostream<char, char_traits<char>>' and 'Color')

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

As an aside, did you know you can enable syntax highlighting by putting the language name after the three backticks?

```c++
// your code here
```
Enter fullscreen mode Exit fullscreen mode

  1. This is sometimes useful, however] 

Collapse
 
dhducky profile image
DHDucky

I've just started coding and just found this interesting to start covering about. Next week there should be one on either scoped enumeration (or struct) so I'll get to learn about what you're talking about. And the thing about the syntax highlighting is much appreciated as this is my first blog/post ever on any type of social media. Have a nice day!