簡體   English   中英

將C ++字符串映射到枚舉以獲取用戶輸入

[英]Mapping c++ string to an enum in order to take user input

我正在嘗試設計一個類來表示我決定使用枚舉來表示等級和花色的牌。 但是,我需要能夠從用戶那里獲取輸入,但是不幸的是,不可能直接從cin中獲取枚舉。

因此,我打算輸入一個字符串,並使用std::map將每個字符串std::map到它表示的枚舉值(如本問題所述 )。 我也不想讓我的輸入區分大小寫,所以我創建了一個正則表達式,在匹配之前應該將所有字符都轉換為小寫。

我想出的代碼在這里:

istream& operator>>(istream& is, Card& d)
{
std::map<std::string,Card::Rank> mr;
std::map<std::string,Card::Suit> ms;
mr[std::regex("/two/i")] = Card::TWO;
mr[std::regex("/three/i")] = Card::THREE;
mr[std::regex("/two/i")] = Card::FOUR;
mr[std::regex("/two/i")] = Card::FIVE;
mr[std::regex("/two/i")] = Card::SIX;
mr[std::regex("/two/i")] = Card::SEVEN;
mr[std::regex("/two/i")] = Card::EIGHT;
mr[std::regex("/two/i")] = Card::NINE;
mr[std::regex("/two/i")] = Card::TEN;
mr[std::regex("/two/i")] = Card::JACK;
mr[std::regex("/two/i")] = Card::QUEEN;
mr[std::regex("/two/i")] = Card::KING;
ms[std::regex("/clubs/i")] = Card::CLUBS;
ms[std::regex("/diamonds/i")] = Card::DIAMONDS;
ms[std::regex("/hearts/i")] = Card::HEARTS;
ms[std::regex("/spades/i")] = Card::SPADES;

string srank, ssuit;
char c1;

if (is >> srank >> c1 >> ssuit)
{
    if (c1 == 'of')
    {
        Card::Rank rank = mr[srank];
        Card::Suit suit = ms[ssuit];
        d = Card(rank, suit);
    }
    else
    {
       is.clear(ios_base::failbit);
    }
}

return is;
}

但是,在編譯時會收到此錯誤:

error C2679: binary '[' : no operator found which takes a right-hand operand of type 'std::basic_regex<_Elem>' (or there is no acceptable conversion)
      with
      [
          _Elem=char
      ]
      c:\program files (x86)\microsoft visual studio 11.0\vc\include\map(173): could be 'Card::Rank &std::map<_Kty,_Ty>::operator [](std::basic_string<_Elem,_Traits,_Alloc> &&)'
      with
      [
          _Kty=std::string,
          _Ty=Card::Rank,
          _Elem=char,
          _Traits=std::char_traits<char>,
          _Alloc=std::allocator<char>
      ]
      c:\program files (x86)\microsoft visual studio 11.0\vc\include\map(190): or       'Card::Rank &std::map<_Kty,_Ty>::operator [](const std::basic_string<_Elem,_Traits,_Alloc> &)'
      with
      [
          _Kty=std::string,
          _Ty=Card::Rank,
          _Elem=char,
          _Traits=std::char_traits<char>,
          _Alloc=std::allocator<char>
      ]
      while trying to match the argument list '(std::map<_Kty,_Ty>, std::basic_regex<_Elem>)'
      with
      [
          _Kty=std::string,
          _Ty=Card::Rank
      ]
      and
      [
          _Elem=char
      ]

etc.

我以前從未使用過地圖,也不太了解自己做錯了什么。 根據我設法挖掘的說明,在我看來這應該可行。

您聲明mr是從字符串到等級的映射。 您正在嘗試使用regex作為鍵。 但是正則表達式不是字符串。 選擇一個,然后持續使用它。

根據您所擁有的解決方案:

std::regex不是std::string ,它們是完全不同的類型。 我也懷疑,如果使用std::regex作為映射鍵,是否可以獲得任何有意義的結果。 更重要的是,std :: map永遠不會像您期望的那樣工作。 如果您想針對正則表達式列表測試字符串並選擇一個匹配的正則表達式,則必須完全這樣做:遍歷所有正則表達式並測試每個正則表達式。 如果您要松散這些正則表達式,則將需要它。

更簡單的方法是將所有讀取的字符串轉換為小寫,然后使用標准字符串映射。 就像是:

#include <cctype>

static inline void stringToLower(std::string &s) {
    for (uint i = 0; i < s.size(); ++i) {
        s[i] = tolower(s[i]);
    }
}

istream& operator>>(istream& is, Card& d)
{
    std::map<std::string,Card::Rank> mr;
    std::map<std::string,Card::Suit> ms;
    mr["two"] = Card::TWO;
    mr["three"] = Card::THREE;
    ...
    mr["king"] = Card::KING;

    ms["clubs"] = Card::CLUBS;
    ...

    string srank, ssuit, c1;

    if (is >> srank >> c1 >> ssuit)
    {
        stringToLower(c1);
        if (c1 == "of")
        {
            stringToLower(srank);
            stringToLower(ssuit);
            Card::Rank rank = mr[srank];
            Card::Suit suit = ms[ssuit];
            d = Card(rank, suit);
        }
        else
        {
            is.clear(ios_base::failbit);
        }
    }

    return is;
}

注意,我將c1更改為字符串。 在yout版本中,c1將是srank之后的第一個字符(它將是一些whiltespace)。 同樣, char值永遠不能等於'of''of'是int類型的)。 我將其更改為類型為const char * "of" (雙引號)。 請記住,如果c1為char* ,它將無法正常工作。

順便說一句,分別為每個<<調用創建mrms映射是非常低效的。 考慮使用某種單例。 可能的解決方案可能是這樣的:

static std::map<std::string,Card::Rank> createmr() {
    std::map<std::string,Card::Rank> mr;
    mr["two"] = Card::TWO;
    mr["three"] = Card::THREE;
    ...
    mr["king"] = Card::KING;
    return mr;
}

static std::map<std::string,Card::Rank> createms() {
    std::map<std::string,Card::Rank> ms;
    ms["clubs"] = Card::CLUBS;
    ...
    return ms;
}

istream& operator>>(istream& is, Card& d)
{
    static std::map<std::string,Card::Rank> mr = createmr(); // note `static` keyword
    static std::map<std::string,Card::Suit> ms = createms();
    ...
}

說明 :我在2個不同的地方使用了static關鍵字。 一種是在functin聲明之前。 static表示該功能在其他源文件中不可用。 我還在mrms聲明中使用了它。 這意味着,這些變量在定義它們的函數的所有調用中都是公用的(在這種情況下,是operator>> )。 這樣的結果是,在運算符的第一次調用中,createmr()和createms()將僅被調用一次。

可能更好的方法是在函數之外定義mrms

static std::map<std::string,Card::Rank> mr = createmr(); // note `static` keyword
static std::map<std::string,Card::Suit> ms = createms();

istream& operator>>(istream& is, Card& d)
{
    ...
}

這里的static關鍵字表示將無法從此源文件外部訪問這些變量(現在為全局變量)。 在這里可以省略它,但是優良作法是將所有將在外部使用的函數和全局變量標記為static

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM