将string用于switch语句(c++做C#的事儿, switch中break还是return厉害)


作为一个C++程序员,或是出于习惯,或是出于无奈,你多少次这么写:

if (!strcmp(pszValue, "Value X"))
    DoThis();
else if (!strcmp(pszValue, "Value Y"))
    DoThat();
else if (!strcmp(pszValue, "Value Z"))
    DoSomethingElse();
else
    DontKnowWhatToDo();

你千百次的问,如果这个时候可以使用switch多好呢?

switch(strValue)
{
case "Value X":
    DoThis();
    break;
case "Value Y":
    DoThat();
    break;
case "Value Z";
    DoSomethingElse();
    break;
default:
    DontKnowWhatToDo();
    break;

上面这段代码在C Sharp中是合法的,但是作为一个C++程序员,你只能无奈和无奈。

下面就是用enum和std::map完成这个愿望!

#include <map>
#include <string>
#include <iostream.h>

// Value-Defintions of the different String values
static enum StringValue { evNotDefined, 
                          evStringValue1, 
                          evStringValue2, 
                          evStringValue3, 
                          evEnd };

// Map to associate the strings with the enum values
static std::map<std::string, StringValue> s_mapStringValues;

// User input
static char szInput[_MAX_PATH];

// Intialization
static void Initialize();

int main(int argc, char* argv[])
{
  // Init the string map
  Initialize();

  // Loop until the user stops the program
  while(1)
  {
    // Get the user's input
    cout << "Please enter a string (end to terminate): ";
    cout.flush();
    cin.getline(szInput, _MAX_PATH);
    // Switch on the value
    switch(s_mapStringValues[szInput])
    {
      case evStringValue1:
        cout << "Detected the first valid string." << endl;
        break;
      case evStringValue2:
        cout << "Detected the second valid string." << endl;
        break;
      case evStringValue3:
        cout << "Detected the third valid string." << endl;
        break;
      case evEnd:
        cout << "Detected program end command. "
             << "Programm will be stopped." << endl;
        return(0);
      default:
        cout << "'" << szInput 
  << "' is an invalid string. s_mapStringValues now contains "
             << s_mapStringValues.size() 
             << " entries." << endl;
        break;
    }
  }

  return 0;
}

void Initialize()
{
  s_mapStringValues["First Value"] = evStringValue1;
  s_mapStringValues["Second Value"] = evStringValue2;
  s_mapStringValues["Third Value"] = evStringValue3;
  s_mapStringValues["end"] = evEnd;

  cout << "s_mapStringValues contains " 
       << s_mapStringValues.size() 
       << " entries." << endl;
}

这里有个特别重要的技巧,那就是为什么把enumeration的第一个设为evNotDefined ?

首先我们要明确std::map::operator[] 的作用: 1 设置一个key的value 2 取值。这个时候需要注意,若不存在,才会被插入。

即程序中对于s_mapStringValues,如果szInput 是新的,将会被插入。 并且 the value默认为0 。 如果enumeration第一项为evStringValue1,任何一个未知的string value 都会导致一个有效的switch case。所以我们才这么干。

============================================================== 这里还有个小问题 讨论一下,就是switch语句中return厉害还是break厉害: 代码:

switch(s_mapStringValues[szInput])
    {
      case evStringValue1:
        cout << "Detected the first valid string." << endl;
        return  0;//还会执行break吗?
        break;
      case evStringValue2:
        cout << "Detected the second valid string." << endl;
        break;
      case evStringValue3:
        cout << "Detected the third valid string." << endl;
        break;
      case evEnd:
        cout << "Detected program end command. "
             << "Programm will be stopped." << endl;
        return(0);
      default:
        cout << "'" << szInput 
  << "' is an invalid string. s_mapStringValues now contains "
             << s_mapStringValues.size() 
             << " entries." << endl;
        break;
    }

测试,表面,return了 就不会break了。