繁体   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