News:

11 March 2016 - Forum Rules

Main Menu

C++ Enumeration error in switch statement

Started by RetroRain, July 22, 2017, 10:47:18 AM

Previous topic - Next topic

RetroRain

I have this code (it's not really a lot as it looks) that, when run, is showing these compiler errors:


In function `void logic()':
`left' undeclared (first use this function)
(Each undeclared identifier is reported only once for each function it appears in.)
`right' undeclared (first use this function)


The problem is, I can't figure out why it is producing this compiler error.

I have a switch statement in the function below, called void logic(), and it checks stop, up, down, left and right.  There is no problem with the first three enumerators, but it has a problem with left and right.  If I comment left and right (so it doesn't execute), the program runs fine.

I don't get it, because the enumators are all declared.  Why is there a problem with left and right?

If it helps any, I am coding with Dev-CPP.


#include <iostream>
#include <conio.h>
using namespace std;

void setup();
void draw();
void logic();

enum direction {stop, up, down, left, right};
direction dir;

int snakeX, snakeY, snakeLength, lives, score;
int roomLength, roomHeight, appleX, appleY, i, j;

int main()
{
    setup();
    draw();
    logic();
    cin.get();
    return 0;
}

void setup()
{
    roomLength = 40;
    roomHeight = 20;
    snakeX = roomLength / 2;
    snakeY = roomHeight / 2;
    appleX = rand() % roomLength;
    appleY = rand() % roomHeight;
    snakeLength = 1;
    lives = 3;
    score = 0;
    dir = stop;
}

void draw()
{
    //first row
    for (i = 0; i < roomLength; i++)
    {
        cout << "+";
    }
    cout << endl;
   
    //the middle rows
    for (j = 1; j < roomHeight-1; j++)
    {
        cout << "+";
        for (i = 1; i < roomLength-1; i++)
        {
            if (i == snakeX && j == snakeY) cout << "O";
            else if (i == appleX && j == appleY) cout << "A";
            else cout << " ";
        }
        cout << "+" << endl;
    }
   
    //last row
    for (i = 0; i < roomLength; i++)
    {
        cout << "+";
    }
}

void logic()
{
    switch (dir)
    {
        case stop:
            break;
        case up:
            snakeY--;
            break;
        case down:
            snakeY++;
            break;
        case left:
            snakeX--;
            break;
        case right:
            snakeX++;
            break;
    }
}


Right where case left and case right are, is where the errors are being pointed out.  Yet I can see no error at all.  There are no typos at all.  You can copy and paste this code yourself in any IDE, and see for yourself.  The header file conio is just for keyboard input that I haven't gotten to yet, so it doesn't matter if it is there or not.

If anyone can tell me why it is producing this error, you can have a giant cookie!





EDIT:

Okay, so I did some searching.  This article tells you that the compiler will give you errors if one of the enumerators is not handled properly (http://en.cppreference.com/w/cpp/language/switch).

So that got me thinking... I tried using single quotes on my enumerator, and the program ran.


void logic()
{
    switch (Edir)
    {
        case stop:
            break;
        case up:
            snakeY--;
            break;
        case down:
            snakeY++;
            break;
        case 'left':
            snakeX--;
            break;
        case 'right':
            snakeX++;
            break;
    }
}


I just had to put left and right in single quotes for it to run.  I most likely have to do that for other three as well, but I honestly didn't know that you had to do that.
My YouTube Channel: RetroRainZX85 - https://www.youtube.com/channel/UCdHK6fSwUlcM-q8_EgZQfdw

Disch

Name collision

using namespace std;

This line will take everything that's in the std namespace and dump it into the global namespace (defeating the whole point of having a separate namespace in the first place).  This includes stuff you don't know about and/or don't want.

This is causing your problem, because there's already a function called "std::left".  But because you're "using namespace std", that left gets dumped into the global namespace and conflicts with your direction left.  (ditto for "right")  So now when you say "left", the compiler doesn't know if you want "std::left" or "direction::left", so it gives you the error.


Solutions:

Approach #1:

Don't use "using namespace std".  This is generally a good idea anyway and is recommended practice.  I don't know why beginner guides always show this line -- it's usually a really bad idea to use it.  Instead, prefix stuff from std with a scope qualifier.  Like  "std::cin" / "std::cout" / "std::endl" ... although you generally don't want to use endl, either... use a newline character ('\n') instead.

Or, if that's too wordy, explicitly state which things from the std namespace you want.  Example:


// instead of this:
using namespace std;  // <- barf, bad, don't do it

// do this:
using std::cout;
using std::cin;
using std::endl;



Approach #2

Qualify your 'left' to be your direction instead of std::left:


case directon::left:
  ...
case direction::right:
  ...




I highly recommend approach #1



EDIT:

Putting 'left' and 'right' in quotes is not a solution, as that changes their type and screws everything up.  It is not doing what you think it's doing.  Don't do that.

RetroRain

Oh okay thanks for clarifying that Disch.  I got the program to run using those single quotes, but even though it ran, I still got compiler warnings.  I had no idea that "using namespace std" was the culprit.

The book I have, C++ Primer Plus, most of the examples, at least most of the parts I have read, have "using namespace std" in the examples.  It does explain the other way of "using std::cout", it's just that most of the examples have used the other way, so I got in the habit of using it.

At least now I know which habit to break. :P  I'm telling ya, C++ is a very complex language.

Thank you for your input.  Oh, and you get a giant cookie for helping. :)

My YouTube Channel: RetroRainZX85 - https://www.youtube.com/channel/UCdHK6fSwUlcM-q8_EgZQfdw

Disch

FWIW, "using namespace" is acceptable in really small one-off programs that you want to crank out really quick.  Particularly when dealing with iostream (which, in general is extremely overly verbose and awful to work with), as it really shortens up the crap you have to type.  But of course that comes with the trade-off of hitting problems like the one you just experienced.

But in larger programs -- yeah you definitely do not want to do that.   :thumbsup:  So yeah, that's a good habit to break early.

Another habit to break before you start:  don't use new/delete directly.  Use smart pointers and containers.  If/when your book talks about new/delete, mostly ignore it and look at examples of std::unique_ptr / std::make_unique, std::shared_ptr / std::make_shared, and std::vector instead.

Quote from: RetroRain on July 23, 2017, 01:07:57 AMI'm telling ya, C++ is a very complex language.

It really is.  In a way, I'm glad it was my first language, because otherwise I would have had a really hard time coming to grips with it.