我必须编写一个带有Enum状态的程序,这是50个2个字母的州缩写(NY,FL等)。我需要制作一个程序,询问用户信息,用户需要输入与该状态对应的2个字母。如何检查其输入是否有效,即与枚举状态{AL,...,WY}中定义的2个字母状态匹配?我想我可以制作一个巨大的if语句来检查输入==“AL”|| ...... || input ==“WY”{do stuff} else {错误输入与状态不匹配},但必须为所有50个状态执行此操作会有点荒谬。有更简单的方法吗?
此外,如果将枚举状态定义为{AL,NY,FL},我如何将用户输入(即字符串)转换为状态?如果我将状态更改为{“AL”,“NY”,“FL”}那会更容易还是有其他方法可以做到?
答案 0 :(得分:1)
不幸的是,C ++没有提供将枚举转换为字符串的可移植方式,反之亦然。可能的解决方案是填充std::map<std::string,State>
(或哈希映射),并在转换时进行查找。您可以手动填充此类映射,也可以创建一个简单的脚本,该脚本将在.cpp文件中生成一个函数,以填充此映射并在构建过程中调用该脚本。您的脚本可以生成if / else语句,而不是填充map。
另一个更困难但更灵活和更稳定的解决方案是使用像llvm这样的编译器并制作一个插件,它将根据编译器生成的语法树生成这样的函数。
答案 1 :(得分:0)
最简单的方法是使用STL std::map
,但是对于可能不允许的学术练习(例如,可能只需要使用课程材料中涵盖的技术)。
除非明确初始化,否则枚举从零开始按顺序整数编号。鉴于此,您可以扫描字符串的查找表,并将匹配的索引转换为枚举。例如:
enum eUSstate
{
AL, AK, AZ, ..., NOSTATE
} ;
eUSstate string_to_enum( std::string inp )
{
static const int STATES = 50 ;
std::string lookup[STATES] = { "AL", "AK", "AZ" ... } ;
int i = 0 ;
for( i = 0; i < STATES && lookup[i] != inp; i++ )
{
// do nothing
}
return static_cast<eUSstate>(i) ;
}
如果您不想依赖于强力转换并以与枚举相同的顺序维护查找表,则可以使用具有字符串和匹配枚举的查找表
eUSstate string_to_enum( std::string inp )
{
static const int STATES = 50 ;
struct
{
std::string state_string ;
eUSstate state_enum ;
} lookup[STATES] { {"AL", AL}, {"AK", AK}, {"AZ", AL} ... } ;
eUSstate ret = NOSTATE ;
for( int i = 0; ret == NOSTATE && i < STATES; i++ )
{
if( lookup[i].state_string == inp )
{
ret = lookup[i].state_enum ;
}
}
return ret ;
}
可以通过利用字母排序和执行二进制搜索来优化查找,但对于50个州来说,这几乎是不值得的。
答案 2 :(得分:0)
你需要的是一张桌子。因为枚举是线性的, 一个简单的字符串表就足够了:
char const* const stateNames[] =
{
// In the same order as in the enum.
"NY",
"FL",
// ...
};
然后:
char const* const* entry
= std::find( std::begin( stateNames ), std::end( stateNames ), userInput );
if (entry == std::end( stateNames ) ) {
// Illegal input...
} else {
State value = static_cast<State>( entry - std::begin( stateNames ) );
或者,你可以有一个数组:
struct StateMapping
{
State enumValue;
char const* name;
struct OrderByName
{
bool operator()( StateMapping const& lhs, StateMapping const& rhs ) const
{
return std::strcmp( lhs.name, rhs. name ) < 0;
}
bool operator()( StateMapping const& lhs, std::string const& rhs ) const
{
return lhs.name < rhs;
}
bool operator()( std::string const& lhs, StateMapping const& rhs ) const
{
return lhs < rhs.name;
}
};
};
StateMapping const states[] =
{
{ NY, "NY" },
// ...
};
按键排序,然后使用std::lower_bound
:
StateMapping::OrderByName cmp;
StateMapping entry =
std::lower_bound( std::begin( states ), std::end( states ), userInput, cmp );
if ( entry == std::end( states ) || cmp( userInput, *entry) {
// Illegal input...
} else {
State value = entry->enumValue;
// ...
}
后者可能稍微快一点,但只有50 条目,我怀疑你会注意到差异。
当然,你不要手动编写这段代码;你生成了 它有一个简单的脚本。 (过去,我有代码可以 解析枚举定义的C ++源代码,并生成 从它们映射功能。它比听起来更简单, 因为你可以忽略大块的C ++代码,除了 跟踪各种嵌套。)
答案 3 :(得分:0)
解决方案很简单,但只对字符串中的2个字符(如您的情况):
#include <stdio.h>
#include <stdint.h>
enum TEnum
{
AL = 'LA',
NY = 'YN',
FL = 'LF'
};
int _tmain(int argc, _TCHAR* argv[])
{
char* input = "NY";
//char* input = "AL";
//char* input = "FL";
switch( *(uint16_t*)input )
{
case AL:
printf("input AL");
break;
case NY:
printf("input NY");
break;
case FL:
printf("input FL");
break;
}
return 0;
}
在上面的例子中,我使用了带有双字符代码的枚举(它是合法的),并将一个输入字符串传递给switch语句。我测试了它的最终工作!请注意枚举中的单词alignment。
Ciao