Comparing combinations of enums with switch? - c++

I need to compare different combinations of two enum values in the same switch and the only way I was doing it so far is by nesting switches like this:
enum enum1
{
A,B,C,D,E,F,G,
H,I,J,K,L,M,N
};
enum enum2
{
O,P,R,S,T,U,V,
Z,X,Y
};
enum1 x;
enum2 y;
switch(x)
{
case A:
switch(y)
{
case O:
// do stuff
break;
}
case B:
switch(y)
{
case O:
// do stuff
break;
}
// etc...
}
This approach makes my switches really long, and I'm trying to implement some different approach to reduce the amount of code...
for example something like this does not work:
int combination = C | P; // combine two enum values (enums from above code)
switch(combination)
{
case (A | P):
// do stuff
break;
case (B | O): // error: duplicate value
break;
}
can you recommend some good approach on how to achieve the best results by not typing too much case this: case that: ?

The problem with the switch is that when calculating the bit-wise OR of the cases the same value appear more than one time (ex: A | P is the same than B | O), if is not assigned a value for the elements of the enum they take values from 0..n, you could assigning specific values to the elements of the enum, in the recommended case they are power of 2 (1, 2, 4, 8, ...) bit flags, this assure you that when apply bit-wise OR there will be no identical values (all elements of the enum have different bit of the int, this mean also, that could not be more than 32 enum elements in total, counting enum1 and enum2).
The first case propose assign values always beginning in 0x1 (in this case a shift is needed to one of the enums because if not the bit flags will collide and could be repeated values again). The macro could and should if C++11 is allowed be change by a constexpr.
The second case (recommended) assign the values to the enum elements already shifted and don't need macro or constexpr.
#include <fstream>
#include <iostream>
#include <vector>
using namespace std;
enum enum1_1 { A = 1, B = 2, C = 4, D = 8 };
enum enum2_1 { O = 1, P = 2, R = 4, S = 8 };
enum enum1_2 { AA = 0x00000001, BB = 0x00000002, CC = 0x00000004, DD = 0x00000008 };
enum enum2_2 { OO = 0x00010000, PP = 0x00020000, RR = 0x00040000, SS = 0x00080000 };
#define COMB(en1, en2) (en1) | (en2 << 16)
int main(int argc, char* argv[]) {
// Case 1
enum1_1 x = A;
enum2_1 y = O;
int combination1 = COMB(x, y);
switch (combination1) {
case COMB(A, O): std::cout << "comb a-o" << std::endl; break;
case COMB(A, P): std::cout << "comb a-p" << std::endl; break;
case COMB(A, R): std::cout << "comb a-r" << std::endl; break;
case COMB(A, S): std::cout << "comb a-s" << std::endl; break;
case COMB(B, O): std::cout << "comb b-o" << std::endl; break;
case COMB(B, P): std::cout << "comb b-p" << std::endl; break;
case COMB(B, R): std::cout << "comb b-r" << std::endl; break;
case COMB(B, S): std::cout << "comb b-s" << std::endl; break;
}
// Case 2
enum1_2 xx = BB;
enum2_2 yy = PP;
int combination2 = xx | yy;
switch (combination2) {
case AA | OO: std::cout << "comb a-o" << std::endl; break;
case AA | PP: std::cout << "comb a-p" << std::endl; break;
case AA | RR: std::cout << "comb a-r" << std::endl; break;
case AA | SS: std::cout << "comb a-s" << std::endl; break;
case BB | OO: std::cout << "comb b-o" << std::endl; break;
case BB | PP: std::cout << "comb b-p" << std::endl; break;
case BB | RR: std::cout << "comb b-r" << std::endl; break;
case BB | SS: std::cout << "comb b-s" << std::endl; break;
}
return 0;
}

Your above approach with using the | symbol only works if you associate unique bit values to each of your code, because you are actually doing an OR operation on the integer bit values. When you define each item, try associating a unique bit with each one.
For example:
enum enum1 {
A = 0x00000001,
B = 0x00000002,
C = 0x00000004,
D = 0x00000008,
E = 0x00000010,
...
};

Bitwise OR'ing the enums as written is going to cause duplicate values, since the enum1 and enum2 domains overlap. If you ensure that the enumerated values in enum1 and enum2 don't share any of the same bits, you should be able to use the bitwise OR technique.
See #user2835484

actually you can combine more than one case in one, as you point in the combination example, but I think the syntax is should be like this:
switch(combination)
{
case A: case P:
// do stuff
break;
case B: case O: // error: duplicate value
break;
}

Related

How to handle value initialized enum class in switch-case

If I have an enum class like so
enum class Enum {
A = 1,
B = 2,
};
I was under the impression that the compiler guarantees that instances of Enum must be either A or B. But I learned that the following is possible
auto instance = Enum{};
cout << (instance == Enum::A) << endl;
cout << (instance == Enum::B) << endl;
cout << static_cast<int>(instance) << endl;
And it prints 0 in all cases. Further I used to think having a switch-case like this is exhaustive
switch (instance) {
case Enum::A:
// do something
break;
case Enum::B:
// do something
break;
}
but apparently it's not, how can I handle a value-initialized instance above?
the enum with value 0 is not much different from any other non-presented value (like 3), you can just handle it with default
switch (instance) {
case Enum::A:
// do something
break;
case Enum::B:
// do something
break;
default:
/* do something with non-presented value*/;
}
also note when used as flag, it's pretty common not all value combination have a name.
switch (instance) {
case Enum(0):
// all flag unset
break;
case Enum::A:
// do something when A
break;
case Enum::B:
// do something when B
break;
case Enum::A | Enum::B : // assume operator | exist
// do something when AB
break;
default:
/* do something with non-presented value*/;
}

Case Statement does not execute

This is a growing source of irritation for me at the moment, when I press the corresponding button for the cases (they're initialized above) they don't actually execute and I'm stuck in the menu.
I'm sure this is ridiculously simple and I'm just not seeing it.
Edit: Added more, upon request
const int POKER = 1;
const int EVAL = 2;
const int EXIT = 3;
const char FIVE_CARD = 'a';
const char TEXAS = 'b';
const char OMAHA = 'c';
const char SEVEN_CARD = 'd';
const char GO_BACK = 'e';
const char MENU[] = "\nPlease choose an option from the following:\n"
"1) Play Poker\n2) Set Evaluation Method\n3) Quit\n: ";
const char POKER_MENU[] = "\nPlease choose your game:\n"
"a) 5 Card Draw\nb) Texas Hold 'Em\nc) Omaha High\n"
"d) 7 Card Stud\ne) Go back\n: ";
int main()
{
int choice = 0;
char poker_choice;
do
{
choice = askForInt(MENU, EXIT, POKER);
switch(choice)
{
case POKER :
do
{
choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);
switch(poker_choice)
{
case FIVE_CARD :
std::cout << "Not implemented yet" << std::endl;
break;
case TEXAS :
std::cout << "Not implemented yet" << std::endl;
break;
case OMAHA :
std::cout << "Not implemented yet" << std::endl;
break;
case SEVEN_CARD :
std::cout << "Not implemented yet" << std::endl;
break;
case GO_BACK :
break;
}
}while(poker_choice != GO_BACK);
case EVAL :
std::cout << "Not implemented yet" << std::endl;
break;
case EXIT :
break;
}
}while(choice != EXIT);
choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);
should be
poker_choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);
Since you mentioned this is inside a method,
There are few things to check here;
Once inside the method, just print poker_choice and see if your the value is getting passed correctly.
Check if all the cases FIVE_CARD, TEXAS are declared as constants of the same data type.
Your error seems to be on this line:
choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);
You test poker_choice in your switch but you assign the value to choice.
It should be:
poker_choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);
// ^^^^^^
switch(poker_choice)
// ...

Optimized way to check the value of a variable with enum members value

Hello I have the code below:
enum {a, b, c, d, ..., z} abc;
int main()
{
int val = 20;
if (val == a || val == b ||val == c||val == d..... || val == z)
{
/*Do something*/
}
}
Is there any other way so that we can skip the OR operation because if there are 1000s of enum members then how can we do ahead with checking with all members.
Please help.
A modern compiler should just be able to optimize such code if, as in your case, the value of the expression is known at compile time. For readability and error checking I think that using a switch would be better:
switch (val) {
case a:;
case b:;
....
// your code goes here
}
As said, performance wise there shouldn't be much difference, the compiler will transform this to a table lookup (or other clever things) if appropriate or completely optimize it out if val is known at compile time.
But you can have the advantage of error checking compilers, here. If you don't have a default case, most compilers will warn you if you omit one of the enumeration constants. Also I think that this is clearer, since it doesn't repeat the evaluation of val all over the place.
other(faster) solution will be the following
bool isInenum (int val)
{
bool retVal = false
switch(val)
{
case a:
case b:
case c:
case d:
{
retVal = true;
}
}
return retVal;
}
Since enumerator values are assigned sequentially, putting an if statement like this would be enough:
if(val<=z)
You could use a map in C++. With a map you can write a compact test without the numerous == and ||.
But you first need to initialize a map and I'm not sure if you can do this initialization in a compact way for an arbitrary enum.
#include <iostream>
#include <map>
using namespace std;
enum abc { a = 1, b = -1, c = 3, d = 0 };
int main()
{
map<int, int> m;
m[a] = m[b] = m[c] = m[d] = 1;
cout << "b is " << ((m.find(b) == m.end()) ? "NOT " : "") << "in m" << endl;
cout << "3 is " << ((m.find(3) == m.end()) ? "NOT " : "") << "in m" << endl;
cout << "10 is " << ((m.find(10) == m.end()) ? "NOT " : "") << "in m" << endl;
return 0;
}
Output (ideone):
b is in m
3 is in m
10 is NOT in m

How do I select a range of values in a switch statement?

When I try to compile I get this error:
1>------ Build started: Project: snake, Configuration: Debug Win32 ------
1> exercise.cpp
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(13): error C2059: syntax error : '>='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(16): error C2059: syntax error : '>='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(19): error C2059: syntax error : '>='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(22): error C2059: syntax error : '>='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(25): error C2059: syntax error : '>'
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(28): error C2059: syntax error : '=='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(34): warning C4065: switch statement contains 'default' but no 'case' labels
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Code:
#include <iostream>
using namespace std;
int main(){
int score;
//Vraag de score
cout << "Score:";
cin >> score;
//Switch
switch(score){
case >= 100:
cout << "a";
break;
case >= 50:
cout << "b";
break;
case >= 25:
cout << "c";
break;
case >= 10:
cout << "d";
break;
case > 0:
cout << "e";
break;
case == 0:
cout << "f";
break;
default:
cout << "BAD VALUE";
break;
}
cout << endl;
return 0;
}
How can I fix this problem? It's a console application, Win32 and my IDE is Windows Enterprise C++ 2010.
I'm learning from Beginning C++ Through Game Programming.
Some compilers support case ranges like case x ... y as an extension to the C++ language.
Example:
#include <iostream>
using namespace std;
int main(){
int score;
//Vraag de score
cout << "Score:";
cin >> score;
//Switch
switch(score){
case 0:
cout << "a";
break;
case 0 ... 9:
cout << "b";
break;
case 11 ... 24:
cout << "c";
break;
case 25 ... 49:
cout << "d";
break;
case 50 ... 100:
cout << "e";
break;
default:
cout << "BAD VALUE";
break;
}
cout << endl;
return 0;
}
GCC 4.9, Clang 3.5.1 and Intel C/C++ Compiler 13.0.1 seem to support it (tried on http://gcc.godbolt.org/). On the other hand, Visual C++ 19 doesn't (tried on http://webcompiler.cloudapp.net/).
In C++ case labels are constant expressions, not expressions in general. You need a chain of if-then-else statements to do what you are trying to do.
Alternatively, you can enumerate the values in the switch. This runs marginally faster (though it does not matter in cases like yours), but it is considerably less readable:
switch(score) {
case 0: cout << "f"; break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10: cout << "e"; break;
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25: cout << "c"; break;
// ...and so on, you get the idea...
}
You can fix this problem by using a series of if/else if statements. Switch/case cannot be used like this in C++.
It can be done using a std::map with switch:
enum Interval {
One,
Two,
Three,
NotFound };
// [0,10[ is One, [10,30[ is Two, [30,55[ is Three
std::map<int,Interval> imap {
{ { 0, One },
{ 10, Two },
{ 30, Three },
{ 55, NotFound } };
Interval ivalue = NotFound;
auto f = imap.lower_bound( value );
if( f != imap.end() ) ivalue = f->second;
switch( ivalue ) {
case One : ...
case Two : ...
case Three : ...
default: ...
}
Switch-case is not a great option for testing ranges. The best option is to use several if :
if (score<0) cout << "BAD VALUE";
if (score == 0) cout << "f";
if (score>0 && score<10) cout << "e";
if (score>=10 && score <25) cout << "d";
if (score>=25 && score <50) cout << "c";
if (score>=50 && score <100) cout << "b";
If running time is an issue, the following solution is faster :
if (score == 0) cout << "f";
else if (score<10) cout << "e";
else if (score <25) cout << "d";
else if (score <50) cout << "c";
else if (score <100) cout << "b";
else if (score>=100) cout << "a";
else cout << "BAD VALUE";
There's a GCC extension that does exactly what you want.
In C++ a switch statement can only match constant integer values:
switch (i)
{
case 1:
//... stuff
break;
case 2:
//... stuff
break;
default:
//... stuff
}
The standard does not allow for this:
6.4.2 The switch statement [stmt.switch]
[...] Any statement within the switch statement can be labeled with one or more case labels as follows:
case constant-expression :
where the constant-expression shall be an integral constant expression (5.19).
In other words, you can only use case-values that expand into a single, integral, "hard" compile time constant (e.g. case 5+6:, enum {X = 3}; ... case X*X:).
The way around this is to use if-statements. E.g., to replace
switch (x)
case 0..100:
you'd instead
if (x>=0 && x<=100)
.
std::map::upper_bound + C++11 lambdas
https://stackoverflow.com/a/35460297/895245 mentioned lower_bound, but we can also get rid of the enum there with lambdas (or inheritance if you don't have it).
#include <functional>
#include <iostream>
#include <map>
int main() {
std::string ret;
const std::map<int,std::function<void()>> m{
{0, [&](){ ret = "too small"; }},
{2, [&](){ ret = "[0,2)"; }},
{5, [&](){ ret = "[2,5)"; }},
{7, [&](){ ret = "[5,7)"; }},
};
const auto end = m.end();
for (auto i = -1; i < 8; ++i) {
auto it = m.upper_bound(i);
if (it == end) {
ret = "too large";
} else {
it->second();
}
std::cout << i << " " << ret << std::endl;
}
}
Output:
-1 too small
0 [0,2)
1 [0,2)
2 [2,5)
3 [2,5)
4 [2,5)
5 [5,7)
6 [5,7)
7 too large
Usage inside methods with static
To use this pattern efficiently inside classes, initialize the lambda map statically, or else you pay n log(n) every time to build it from scratch.
Here we can get away with the {} initialization of a static method variable: Static variables in class methods , but we could also use the methods described at: static constructors in C++? I need to initialize private static objects
It was necessary to transform the lambda context capture [&] into an argument, or that would have been undefined: const static auto lambda used with capture by reference
Example that produces the same output as above:
#include <functional>
#include <iostream>
#include <map>
#include <string>
class RangeSwitch {
public:
void method(int x, std::string &ret) {
static const std::map<int,std::function<void(std::string&)>> m{
{0, [](std::string &ret){ ret = "too small"; }},
{2, [](std::string &ret){ ret = "[0,2)"; }},
{5, [](std::string &ret){ ret = "[2,5)"; }},
{7, [](std::string &ret){ ret = "[5,7)"; }},
};
static const auto end = m.end();
auto it = m.upper_bound(x);
if (it == end) {
ret = "too large";
} else {
it->second(ret);
}
}
};
int main() {
RangeSwitch rangeSwitch;
std::string ret;
for (auto i = -1; i < 8; ++i) {
rangeSwitch.method(i, ret);
std::cout << i << " " << ret << std::endl;
}
}
That's simply not how switch works. It only takes single values. You'll have to use if-elseif blocks
I had the same problem with a score based problem and while the " if/elseif "statements were good to use, for intervals i found that the best option (for me at least because i like how it looks and it's easier for me as a beginner to see my mistakes) is " 1 ... 10 ". but don't forget to use a space between the number and the dots or the program will think that your interval is a number and u will get an error "2 many decimal dots...". Hope it helps.
int score;
int main()
{
cout<<"Enter score"<<endl;
cin>>score;
switch(score){
case 100:
cout<<"Your score is Perfect"<<endl;
break;
case 90 ... 99:
cout<<"You got A"<<endl;
break;
case 80 ... 89:
cout<<"You got B"<<endl;
break;
case 70 ... 79:
cout<<"You got C"<<endl;
break;
case 60 ... 69:
cout<<"You got D"<<endl;
break;
case 50 ... 59:
cout<<"You got E"<<endl;
break;
case 0 ... 49:
cout<<"You got F"<<endl;}
}
Switch case statements are a substitute for long if statements that compare a variable to several "integral" values ("integral" values are simply values that can be expressed as an integer, such as the value of a char). The condition of a switch statement is a value. The case says that if it has the value of whatever is after that case then do whatever follows the colon. The break is used to break out of the case statements.
Therefore, you cannot use such conditional statements in case.
The selective structure: switch
This is what worked for me. dividing the mark by 10 and then setting case 10 and 9 to display an "A"(this will display a "A" for any value between 90-100. Then case 8 to display "B", then case 7 will display a "C" for the values from 70-79 and so on.
#include <iostream>
using namespace std;
main ()
{
int mark;
cout << "enter your mark: ";
cin >> mark;
switch (mark/10)
{
case 10: case 9: cout << "A"; break;
case 8: cout << "B"; break;
case 7: cout << "C"; break;
case 6: cout << "D"; break;
case 5: cout << "PASS"; break;
default: cout << "FAIL"; break;
}
}
You can do the following:
//summarize the range to one value
If score < 0
score = -1
switch(score){
case 1:
//...
break;
case 2:
//...
break;
case -1: //complete neg. range
//...
break;
//...
}
Something like this?
case 'A'..'Z' where a not in ['I','L','O']:
Unfortunately no compiler I know of implements that particular extension, though GCC has can do ranges as other answers pointed out. For portability you can cut and paste this DWTFYW licensed snippet. If you're using a custom enum you might resort to code generation to make something similar.
#define CASE_NUMBER \
case'0':case'1':case'2':case'3':case'4':\
case'5':case'6':case'7':case'8':case'9'
#define CASE_ALPHA_LOWER \
case'a':case'b':case'c':case'd':\
case'e':case'f':case'g':case'h':\
case'i':case'j':case'k':case'l':\
case'm':case'n':case'o':case'p':\
case'q':case'r':case's':case't':\
case'u':case'v':case'w':case'x':\
case'y':case'z'
#define CASE_ALPHA_UPPER \
case'A':case'B':case'C':case'D':\
case'E':case'F':case'G':case'H':\
case'I':case'J':case'K':case'L':\
case'M':case'N':case'O':case'P':\
case'Q':case'R':case'S':case'T':\
case'U':case'V':case'W':case'X':\
case'Y':case'Z'
#define CASE_ALPHA CASE_ALPHA_UPPER:CASE_ALPHA_LOWER
#define CASE_ALPHANUM CASE_ALPHA:CASE_NUMBER
If you access to GHCI such as the online version at https://ghc.io/ you might just generate what you need and paste that into a header e.g.
foldl (++) "" ["case" ++ show x ++ ":" | x <- ['A'..'Z'], not $ x `elem` ['I','L','O']]
Here's a way which I hope is expressive and simple to follow.
You may be surprised by how far gcc/clang etc can optimise the code it generates. I would expect it to be at least as efficient as a switch/case.
#include <iostream>
template<class Value>
struct switcher
{
constexpr switcher(Value const& value) : value_(value) {}
constexpr switcher(Value const& value, bool enabled) : value_(value), enabled(enabled) {}
template<class From, class To, class F>
constexpr auto in_range(From&& from, To&& to, F&& f)
{
if (enabled and (from <= value_ and value_ <= to))
{
f();
return switcher(value_, false);
}
else {
return *this;
}
};
template<class F>
constexpr auto otherwise(F&& f)
{
if (enabled)
f();
}
Value const& value_;
const bool enabled = true;
};
template<class Value>
constexpr auto decision(Value const& value)
{
return switcher<Value>(value);
}
void test(int x)
{
decision(x)
.in_range(0, 10, [&] { std::cout << x << " maps to option A\n"; })
.in_range(11, 20, [&] { std::cout << x << " maps to option B\n"; })
.otherwise([&] { std::cout << x << " is not covered\n"; });
}
int main(int argc, char **argv) {
test(5);
test(14);
test(22);
}
A potentially useful insight is that switch accepts an expression, so you can fold multiple input values down to one switch case. It's a big ugly, but for consideration:
switch (score / 10)
{
case 10:
cout << "a";
break;
case 9: case 8: case 7: case 6: case 5:
cout << "b";
break;
case 4: case 3:
cout << "c";
break;
case 2:
if (score >= 25)
{
cout << "c";
break;
}
// else fall through...
case 1:
cout << "d";
break;
case 0:
cout << (score > 0 ? "e" : "f");
break;
default:
cout << "BAD VALUE";
break;
}
Of course, you could have divided by 5 and had case 4: (for 20-24) vs case 5: (25-29) rather than an if inside case 2:, but /10 is arguably more intuitive.
I know this is an old questiion, but since switch statements are in fact wrappers around labels, I find goto may be of (good) use here.
int value = 40;
if (value < 10) {
std::cout << "value < 10" << std::endl;
goto end;
}
if (value < 50) {
std::cout << "value < 50" << std::endl;
goto end;
}
if (value > 30) {
std::cout << "value > 30" << std::endl;
goto end;
}
end:
// resume
This way, you can omit all the elses and keep it compact.
You ought to be careful when using goto though (in general).

How to use enumeration types in C++?

I do not understand how to use enumeration types. I understand what they are, but I don't quite get their purpose.
I have made a program that inputs three sides of a triangle and outputs whether or not they are isosceles, scalene, or equilateral. I'm suppose to incorporate the enumeration type somewhere, but don't get where and how to use them. Any help would be appreciated.
#include <iostream>
using namespace std;
enum triangleType {scalene, isosceles, equilateral, noTriangle};
triangleType triangleShape(double x, double y, double z);
void printTriangleShape(triangleType shape);
int main()
{
double x, y, z;
triangleType scalene, isosceles, equilateral, noTriangle;
cout << "Please enter the three sides of a triangle:" << endl;
cout << "Enter side 1: ";
cin >> x;
cout << endl;
cout << "Enter side 2: ";
cin >> y;
cout << endl;
cout << "Enter side 3: ";
cin >> z;
cout << endl;
triangleType t = triangleShape(x, y, z);
printTriangleShape(t);
return 0;
}
triangleType triangleShape(double x, double y, double z)
{
triangleType scalene, isoceles, equilateral, noTriangle;
if (((x+y) > z) && ((x+z) > y) && ((y+z) > x))
{
cout << "You have a triangle!" << endl;
if (x == y && y == z)
return equilateral;
else if (x == y || x == z || y == z)
return isosceles;
else
return scalene;
}
else if ((x+y) <= z || ((x+z) <= y) || ((y+z) <= x))
return noTriangle;
}
void printTriangleShape(triangleType shape)
{
switch (shape)
{
case scalene: cout << "Your triangle is Scalene!" << endl;
break;
case isosceles: cout << "Your triangle is an isosceles!" << endl;
break;
case equilateral: cout << "Your triangle is an equilateral!" << endl;
break;
}
}
It's a value, and you probably want to return it from your function.
Try:
triangleType triangleShape(double x, double y, double z) {
if (...) {
return scalene;
} else if (...) {
return isosceles.
} else if (...) {
return equilateral
} else {
return noTriangle;
}
}
Note, you can print the result, but it will print as an integer:
scalene = 0, isosceles = 1, ...
Edit, for printing you may want to do this:
void printTriangleShape(triangleType shape) {
switch (shape) {
case scalene:
cout << "Your triangle is Scalene!" << endl;
break;
case isosceles:
cout << "Your triangle is isosceles!" << endl;
break;
...;
}
}
In C enums make debugging easier because often debuggers print the name value rather than a numeric value. They also allow the compiler to enforce places where it can determine that an invalid value is being stored into an enum variable.
In C++ there is also another benifit, which is that you can use enum types in overloads.
For instance, you could:
ostream & operator<<(ostream & ostr, triangleType t) {
string s;
switch (t) {
case scalene:
s = "scalene";
break;
case isosceles:
s = "isosclese";
break;
case equilateral:
s = "equilateral";
break;
case noTriangle:
s = "noTriangle";
break;
default:
s = "error bad triangle type";
break;
}
return cout << s;
}
and then in main do
cout << "Your triangle is" << t << endl;
An enumeration can be used to identify 'types' of objects, as you are in your case.
For example, your triangle shape method could return a triangleType and that way you could do all of the cout << "..." in your main method and separate the display logic from the triangle object.
The idea is to replace using numbers (1,2,3...) that don't explain their meaning with tags that do have meaning (red, green, blue...). Numbers used in code that only you understand the meaning of are called "magic numbers" and should be avoided since it keeps others from understanding your code.
An enum is a new type in c++. Using this type creates additional type safety as you are only allowed to use the values that are defined for that enum. Enum values will get numbered automatically unless you specify a value yourself, which should be rarely needed. An example:
enum Color { Red, Green, Blue }; // Red = 0, Green = 1, Blue = 2
enum Shape { Circle, Square }; // Circle = 0, Square = 1
int printColor(Color c)
{
// do something with the color here, for example print it.
switch(c)
{
case Red:
cout << "Red";
break;
case Green:
cout << "Green";
break;
case Blue:
cout << "Blue";
break;
}
}
int main(int argc, char* argv[])
{
printColor(Red); // works
printColor(0); // will give an error or warning in C++.
// However, C does less type checking and allows this.
printColor(Circle);
// error, the type is wrong even if the values are identical.
}
You get added type safety in the printColor(0) call -- c++ does additional type checking here, so you can't mistakenly put an invalid number in the call. You can of course achieve the same result with using #define for the values or even put them directly, but in that case the compiler won't be able to warn you if you put in invalid values.