3

Is it possible to have raw values for Enumerations in C++?

Swift Example:

enum AnOperations: String {
    case Addition = "+"
    case Subtraction = "-"
    case Division = "/"
}

// if or switch
if AnOperations.Addition.rawValue == "+" {
    print("true")
}
HelloWorld
  • 332
  • 1
  • 4
  • 18
  • 3
    What is a "raw value"? – Nicol Bolas Nov 01 '19 at 06:17
  • In C, enums have to be assigned to a int (I believe). In Swift, you can assign it to a string, a character, or a value of any integer or floating-point type. Is this possible for C++ for a string and can it be used to be compared with another string (ie if Addition (an enum) == "+") – HelloWorld Nov 01 '19 at 06:20
  • Your example is using strings made of a single character. If you change them to characters (‘+’ instead of “+”) it will work because characters are integers. If you need strings, you will have to put them in a string-function map. – zdf Nov 01 '19 at 07:08
  • What you're looking for is a std::unordered_map perhaps – nada Nov 01 '19 at 07:33

3 Answers3

4

I must admit that I don't know anything about Swift except its name.

In C++, strings may not be used in enumerations.

Enumeration Declaration:

An enumeration is a distinct type whose value is restricted to a range of values (see below for details), which may include several explicitly named constants ("enumerators"). The values of the constants are values of an integral type known as the underlying type of the enumeration.

(Emphasize mine.)

What might work:

enum AnOperations: char {
  Addition = '+',
  Subtraction = '-',
  Division = '/'
};

because char is one of the integral types.

Sample:

#include <iostream>
#include <sstream>

int main()
{
  enum AnOperations: char {
    Addition = '+',
    Subtraction = '-',
    Division = '/'
  };
  std::string text = "1 + 2";
  std::istringstream in(text);
  int arg1, arg2, result; char op;
  in >> arg1 >> op >> arg2;
  switch (op) {
    case Addition: result = arg1 + arg2; break;
    case Subtraction: result = arg1 - arg2; break;
    case Division: result = arg1 / arg2; break;
    default:
      std::cerr << "Unknown op. '" << op << "'!\n";
      return 1;
  }
  std::cout << arg1 << ' ' << op << ' ' << arg2 << " = " << result << '\n';
  return 0;
}

Output:

1 + 2 = 3

Live Demo on coliru

Scheff's Cat
  • 16,517
  • 5
  • 25
  • 45
  • is there a way to check if the enum "value" exists? (ie AnOperations.contains("+")? – HelloWorld Nov 01 '19 at 06:39
  • I'm afraid not. I remember roughly a nice Q/A about this but I've to dig a little bit. – Scheff's Cat Nov 01 '19 at 06:41
  • That would be great! Thank you! – HelloWorld Nov 01 '19 at 06:41
  • 1
    @HelloWorld I found this: [SO: How to check if enum value is valid?](https://stackoverflow.com/a/4969304/7478597). How to ensure that all `enum` values are considered in `switch()`? That's not easy - not supported by language itself. I remember that `gcc` has a warning for this which can be enabled. – Scheff's Cat Nov 01 '19 at 06:44
  • hmm, good to know! Worst case, I'll continue using if statements. – HelloWorld Nov 01 '19 at 06:49
  • @HelloWorld Even with the limitations of `enum` and `switch`, I would prefer them over `if`/`else` cascades. (The latter look even ugly, don't they?) The `default` branch of `switch` is fine to catch anything which is not a valid `char` in your case. That it doesn't appear in `enum` is practical no problem. – Scheff's Cat Nov 01 '19 at 06:52
  • So you guessed right, I'm building a calculator. I was hoping to use an `enum` as a catch all instead of a vector (still trying to figure out some good options). ie if the string is "+", "-", "/"..., do this generalized code. 100% agree, `Enums` are preferable and more "pretty". But I think the option to check something along the lines of (aVector.contains(aString)) is really nice instead of a bunch of `or`'s. Any suggestions are appreciated. – HelloWorld Nov 01 '19 at 07:05
  • Concerning Calculator, I once wrote another answer: [SO: Tiny Calculator Project](https://stackoverflow.com/a/46965151/7478597). ;-) Though, it's not so tiny as the name applies and `enum`/`switch` are the least interesting detail. – Scheff's Cat Nov 01 '19 at 07:08
1

you can use for char type in C++.
below works

enum AnOperations : char {
    ADDITION='+',
    SUBSTRACTION='-',
    DIVISION='/'
};

below error in compile time

enum AnOperationsSTR : std::string {
    ADDITION = '+',
    SUBSTRACTION = '-',
    DIVISION = '/'
};
or
enum AnOperationsSTR : char[] {
    ADDITION = '+',
    SUBSTRACTION = '-',
    DIVISION = '/'
};

so, you can use like below.

int main(void)
{
    printf("is %c == AnOperations:'+' : %s\n", '+', AnOperations::ADDITION == '+' ? "TRUE" : "FALSE");
    printf("is %c == AnOperations:'+' : %s\n", '+', AnOperations::SUBSTRACTION == '+' ? "TRUE" : "FALSE");
    return 0;
}

result of above code is,

is + == AnOperations:'+' : TRUE
is + == AnOperations:'+' : FALSE
1

As others already said, you cannot switch on a string, but you could use a map to achieve the same outcome. Depending on your purpose, it might be overkill.

void f( const char* s )
{
  using function_t = std::function< void() >;
  using string_to_function = map< string, function_t >;

  static string_to_function m =
  {
    {"1234", f_1234}, // assosciate "1234" to function f_1234
    {"ABCD", f_ABCD}, // assosciate "ABCD" to function f_ABCD
  };

  auto i = m.find( s );

  return i == m.end()
    ? f_default() // not found in map
    : i->second(); // found, so we call the function
}

Demo

And, just for fun, try this:

#include <iostream>

void f( int i )
{
  switch ( i )
  {
  default: cout << "default"; break;
  case 'ABCD': cout << "ABCD\n"; break;
  case '1234': cout << "1234\n"; break;
  }
}

int main()
{
  f( '1234' );
  f( 'ABCD' );
}
zdf
  • 3,363
  • 2
  • 14
  • 25