I have this code:

#include <iostream>

using namespace std;

int main()
{
        enum foxtrot {green, yellow, red};
	foxtrot colorSelect;

        cout << red << endl;
	cin >> colorSelect;
	cout << colorSelect << endl;
}

Line 10 gives me the result 2 as expected, but line 11 gives me a compile error: "No match for 'operator<<' in 'std::cin << colorSelect'.

I thought I was entering this right but...am I? What am I doing wrong here, I thought it was pretty straight forward.

I guess that means you should input to an int and then check the range of the int and then copy the int to the enum type variable.

But isn't an enum already creating its own type? Here's where I'm confused:

On this site there's an example:
http://www.cplusplus.com/doc/tutorial/other_data_types/#enum

enum colors_t {black, blue, green, cyan, red, purple, yellow, white}; 

colors_t mycolor;
 
mycolor = blue;
if (mycolor == green) mycolor = red;

In this above example it looks like they create a variable called 'mycolor' FROM the new enum data type 'colors_t'. Later they change the value of 'mycolor' to be 'blue'. I was assuming this could be a cin line from the user, not just under the hood. Of course, here they're also comparing the values like you mentioned.

Is it possible for the 'cin' to work directly with 'mycolor' here, or would you need to create an int as the only way to do that? It seems like that's not the only way, otherwise why does line 5 work in the above example? It's taking a value that's not an int there.

I guess that means you should input to an int and then check the range of the int and then copy the int to the enum type variable.

Is it possible for the 'cin' to work directly with 'mycolor' here, or would you need to create an int as the only way to do that? It seems like that's not the only way, otherwise why does line 5 work in the above example? It's taking a value that's not an int there.

The way the expression cin >> foo works is that it calls a function with signature istream& operator>>(istream&, type_of_foo&) where type_of_foo is the type of the variable foo.

The expression cin >> foo is another way to write the expression operator>>(cin, foo) , which is a function call. It just calls the function, which does nothing magical, it reads a few characters off of the input stream and does some math on them to convert them to whatever value of type type_of_foo they were representing, and then writes that value to the variable.

It takes the value cin (which is just a global variable containing a value somewhere) as its first argument.

There are definitions of this function for a whole bunch of types. There's definitions of istream& operator>>(istream&, double&) , istream& operator>>(istream&, string&) , and so on. Different functions can have the same name (which in this case is "operator>>") as long as they have different argument types.

There is no definition of the function istream& operator>>(istream&, color_t) anywhere. C++ does not automatically define such functions just because you've created an enumeration type. You could write such a definition yourself though.

If you're early enough into C++ that you don't really know what a function is or what I'm talking about, the main takeaway here is that "cin" operations are not built into the C++ language and that you or some library author has to define them yourself.

Edited 5 Years Ago by Rashakil Fol: n/a

Hi,

if Rashakil's explination is beyond you, you can use a typecast to treat your enum as say an integer. whilst it looks a bit uglier and can down the line cause subtle problems. But if you dont want to or dont understand how to write an overloaded operator you can use something like one of the following:

cin >> (int)colorSelect ; /* old c sytle cast - not the best method but it works */
cin >> static_cast< int >( colorSelect  ); /* c++ version of the c style cast, this one works at compile time */
cin >> dynamic_cast< int >( colorSelect ); /* another c++ cast, this one does sanity checking at run time but is therefore slower */

These will tell the compiler to treat your enum variable as an int but doing so means that you can get the following case where the user can enter invalid values and potentially cause undefined results or a crash.

enum enum_colour_t { red = 0, blue, green};

void getNewColourFromUser( enum_colour_t& newColour )
{
  cin >> static_cast< int >( newColour);
 /* !!! the compiler will allow any valid integer into your enum variable*/
} 

void printColour( const enum_colour_t& colour )
{
  switch( colour )
  {
    case red :
    {
      /* printing code here */
    }
    break;
 

    /* ... more cases */

    default:
    {
      /* you will need a default case here, you cannot assume a valid enum as
       * the cin used before allows any valid integer into the enum.
       * However, it is good coding practise to ALWAYS have a default case with a  switch
       */
    }
  }
}

Basically if you do write an input operator you can sanitise the input using a switch and then if the input value is out of range set the variable to some known default state so that the value of an enum always represents a valid enum value which is a good thing.

I hope that helps you and whilst i have provided a dirty hack method which in some cases is acceptable i would advise you to learn both function programming and then operator overloading which will provide the safest and most powerful solution shown above by Rashakil.

Edited 5 Years Ago by Kanoisa: n/a

Wow thanks to both of you. I think it's a little over my head to go those routes but it definitely helped. I'm realizing that the easiest thing to do is simply create an int var to use for referencing the enum right? Also, for the lamen or early learner's purposes "No, the user cannot define the value of an enum value. Enums are not meant for direct input from the user, generally speaking." ...right?

Hi,

if Rashakil's explination is beyond you, you can use a typecast to treat your enum as say an integer.

This won't work. Your code won't compile, and even if it could compile, it would not work properly at runtime. (That's why it doesn't compile. Casting between references to different integral types, which is probably what you actually wanted, also wouldn't necessarily work properly at runtime, and I don't think why you'd think it would, unless you were severely confused. Making stuff up is a deprecated form of autodidacticism. In the future, you should try something that involves facts.)

Comments
Thanks for the correction

Enumerations are constant expressions with static duration which means they cannot be modified during runtime.The declaration

enum foxtrot {green, yellow, red};

is equivalent with

typedef enum {green,yellow,red} foxtrot;

in which case you are creating an alias for each enumeration's type.You need an explicit cast (type conversion) as Kanoisa mentioned and since the two types are primitive and share the same size (4 bytes) this is ok.An alternative to the above implementation would be a std::map container.Ex

#include <map>
#include <iostream>
#include <utility>
#include <string>

struct color {
   std::string name;
   color () {}
   color (const std::string str) : name(str) {}
   ~color () {}
   operator std::string () {
      return name;
    }
 };

int main ()  {
   std::map <int,color> arr;
   color red("red");
   color blue("blue");
   arr.insert (std::make_pair(1,red));
   arr.insert (std::make_pair(2,blue));
   std::cout << std::string(arr[1]) << "\t" << std::string(arr[2]);
}

in which case you are creating an alias for each enumeration's type.You need an explicit cast (type conversion) as Kanoisa mentioned and since the two types are primitive and share the same size (4 bytes) this is ok.

They are not the same size. The only think you know about the enumeration type is that it's big enough to hold all the enumeration values. You don't know how many bytes it is, and different enumeration types can have different sizes.

You're right but wouldn't an default uninitialized enum be assumed to be of int?I mean it wouldn't make much sense for a long long variable to hold a value of say .. 1

You're right but wouldn't an default uninitialized enum be assumed to be of int?I mean it wouldn't make much sense for a long long variable to hold a value of say .. 1

It could be a signed char, or a signed short, or... I guess it could be an unsigned type, but I don't really know.

Ooh, Thanks for that Rashakil,

I was sure i had done a striaght typecast before but your totally right, have to cin>> nonEnumVar; and then typecast that var to the enum type to assign its value to the enum variable.

My aplogies

This article has been dead for over six months. Start a new discussion instead.