Expression not constant in switch statement?

Hello, i started a thread last week about a problem i had and i couldnt solve it.
I got a tips to use constexpr but i felt it would make my code very unstructured after a while. I am starting a new thread because.

1. I wont get more responses on the last one now.
2. This is a bit different thread than the last one

So now i have made up an example to reproduce the problem i had in my last thread.

So my problem is. I have a global namespace which contains a TileType pointer.
when i am trying to use this in a case expression i get told by the compiler that my expression isnt constant. Why is that?

Thank you in advance.

here is the main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

#include "global.h"
#include "test.h"

global::TileType * global::GrassTile = new global::TileType(1,5,4);

void main()
{
	int i = 1;

	switch(i)
	{
	case global::GrassTile->ID: //<-This is the line i am getting the error on
		//do something
		break;
	}
	
	char f;
	std::cin >> f;
}


Here is the global namespace.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
namespace global
{
	class TileType{
	public:
		const int ID;
		const int Properties;
		const int TextureID;
		TileType(int PID,int PProperties,int PTextureID):
		ID(PID),
		Properties(PProperties),
		TextureID(PTextureID)
		{

		}

	};

	extern TileType * GrassTile;
}
case statements can only handle constant values, either through literals or const declaration. If you need to use variables in the checks, use if statements instead.
Using if statements sounds like a possible solution, tho it sounds like an "ugly" solution. I tried const declaration and i still got the same error. Maybe i did something wrong. Can you please edit my code and show how you mean?

By the way, what is literals? Never heard that word before.
Last edited on
case values must be known at compile time. An int variable it not known at compile time.

Would an enum work for what you want to do?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
typedef enum tiletype_enum 
    { tt_grass = 1, 
       tt_rock = 2, 
       tt_sand = 3
    } tiletype_t;

class TileType
{  tiletype_t   tt;
public:
    // Cast to return the tile type as an enum
    operator tiletype_t () const
    { return tt;
    }
};

TileType * SomeTile;

void main()
{   
    switch(*SomeTile)
	{
	case tt_grass: 
	    //do something
	    break;
	}
}
Last edited on
I have never used enums, i have just read about the slightly but this might be the time for me to start use them, i think they will do what is required, Thank you for your help i will mark this as solved now!
Ok i got stuck again, I dont really understand your last reply. I thought i did earlier but i didnt,

I will post my code as it is now. Maybe you can take a look at it and tell me what i can do about it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
namespace global
{
	enum TileID
	{
		GRASS,
		ROAD_DIRT,
		TOWER_ARROW
	};

	enum TileProperties
	{
		ENVIROMENT,
		ROAD,
		TOWER
	};

	extern const unsigned int GrassTexture;

	class Tile{
	public:

		Tile(TileID PID,TileProperties PProp, unsigned int PTextureID):
		ID(PID),
		Properties(PProp),
		TextureID(PTextureID)
		{
		}

		TileID getID()
		{
			return (TileID) ID;
		}

		TileProperties getProperties()
		{
			return (TileProperties) Properties;
		}

		const unsigned int getTextureID()
		{
			return (const unsigned int) TextureID;
		}

	private:
		TileID ID;
		TileProperties Properties;
		const unsigned int TextureID;
	};

	extern Tile * Grass;
}


I have learned c++ totally by myself and i have probaly missed som parts.
I must ask you what do these lines do.

1
2
3
 operator tiletype_t () const
    { return tt;
    }


I know the operator keyword. But i didnt really understood this. Is it some typecasting?
Yes, it's a cast operator. In this case it allows us to refer to a Tile object as if it were a TileID.

Your Tile class has several private variables (ID, Properties and TextureID). Since they are private we can't access them outside the class, so if we want to use them we have two choices:
1) write a "getter" function, as you did with getID()
2) Use a cast operator
1
2
3
4
5
6
 
  operator TileID () const
  { return ID;
  }

  TileID id = (TileID)(*Grass);

The explicit cast (in bold) is not required since by defining the cast, the compiler know how to convert a Tile reference to a TileID.
 
TileID id = *Grass; 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
TileID getID()
		{
			return (TileID) ID;
		}

		TileProperties getProperties()
		{
			return (TileProperties) Properties;
		}

		const unsigned int getTextureID()
		{
			return (const unsigned int) TextureID;
		}


Why are you casting these? They are already the correct type; this could only create errors later down the line if you change the type.
Now that is true, Why did i do that? haha

Well thank you for your Reply AbstractAnon i will take a look at it later.
I am still getting the same error that is telling me that the expression is not constant.

I probaly didnt understood how you meant again, but i will post all of my current code.


Here is main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>

#include "global.h"
using namespace std;

const unsigned int global::GrassTexture = 1;

global::Tile * global::Grass = new global::Tile(global::GRASS, global::ENVIROMENT, global::GrassTexture );

void main()
{
	cout << global::Grass->getID() << endl;                  //All of those works fine
	cout << global::Grass->getProperties() << endl;
	cout << global::Grass->getTextureID() << endl;

	int i = global::ENVIROMENT;

	switch(i)
	{
	case global::Grass->getID(): //This is the error line, Expression is not constant!
	}

	char f;
	cin >> f;
}


Here is global namespace

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
namespace global
{
	enum TileID
	{
		GRASS,
		ROAD_DIRT,
		TOWER_ARROW
	};

	enum TileProperties
	{
		ENVIROMENT,
		ROAD,
		TOWER
	};

	extern const unsigned int GrassTexture;

	class Tile{
	public:

		Tile(TileID PID,TileProperties PProp, unsigned int PTextureID):
		ID(PID),
		Properties(PProp),
		TextureID(PTextureID)
		{
		}




		operator TileID () const
		{ return ID;
		}

		operator TileProperties () const
		{return Properties;
		}

		TileID getID()
		{
			return ID;
		}

		TileProperties getProperties()
		{
			return Properties;
		}

		const unsigned int getTextureID()
		{return TextureID;
		}

	private:
		TileID ID;
		TileProperties Properties;
		const unsigned int TextureID;
	};

	extern Tile * Grass;
}
Last edited on
closed account (zb0S216C)
Case labels must be known at compile-time; functions are executed during run-time. Just because a variable/object is declared constant, it doesn't mean it will be evaluated at compile-time.

Wazzak
Last edited on
Declaring that one constant didnt change anything
Not sure what you tried to change to const, but as Framework pointed out, you can't use a function call as a case label.

Also, youa code isn't making a whole lot of sense.

Here you're assigning a constant (the enum value of ENVIRONMENT) to an int. Not a good idea, since you loose the type of what ENVIRONMENT is (TileProperties).
 
int i = global::ENVIROMENT;


Then you switch on the value of i (which was a constant)
1
2
3
4
5
switch(i)
{  case global::Grass->getID(): 
         // some code
         break;
}

What is it that "some code" is supposed to be doing? Is it related to TileProperties or to TileID?

What I think you want is something along these lines:
1
2
3
4
5
6
7
8
9
10
TileID  id;

id = sometile->getID();
switch (id)
{
case GRASS: //Do something related to grass
                     break;
case ROAD_DIRT:  // Do something related to road dir
                     break;
}

or, the following:
1
2
3
4
5
6
7
8
9
10
TileProperties tp;

tp = sometile->getProperties();
switch (tp)
{
case ENVIRONMENT:  // Do something related to the environment
                                 break;
case ROAD:  // Do something related to the road
                    break;
}





Last edited on
Sorry, when i look at this solution i realize ive been really stupid. Now it works just fine and the code looks structured.

Ive been on LAN with a friend for a few days with not much sleep. Sorry for bothering. But thank you for your help alot.

Now this is solved!
Topic archived. No new replies allowed.