2

编辑:

我知道如果它是一个,这会很容易enum,但我不能enum在这个特殊场合使用一个。我实际上需要一个字符串进行进一步处理。


例如,我有四个状态字符串:

IDLE, STARTED, STOPPED, PAUSED

以及吸收以下状态之一的功能:

setState(const std::string &state);

有没有一种快速的方法来验证输入状态是四个字符串之一,而不使用这样的巨型if语句:

if (state == "IDLE" || state == "STARTED" || state == "STOPPED" || state == "PAUSED") { 
// use code
}
4

5 回答 5

9

最好的方法是始终使用枚举。但是如果你必须坚持使用 std::string,那么我会推荐这样的东西:

#include <unordered_set>

static void setState(const std::string &state)
{
    static std::unordered_set<std::string> states {{ "IDLE", "STARTED", "STOPPED", "PAUSED" }};
    if (states.find(state) == states.end())
        throw std::invalid_argument("Invalid state");

    // Continue...
}
于 2013-09-13T18:42:29.767 回答
3

尝试:

std::string tmp[] = {"IDLE", "STARTED", "STOPPED", "PAUSED"};
std::set<std::string> allowedStates(tmp, tmp + sizeof(tmp) / sizeof(tmp[0]));

(可能在静态变量或其他东西中)

接着:

if (allowedStates.find(state) == allowedStates.end())
{
  //state is invalid
}
于 2013-09-13T18:42:51.877 回答
1

这取决于您所说的“快速方式”是什么意思。如果这是关于效率,我会首先打开大小:

bool verify_state( const std::string& state ) {
  switch( state.size() )
  {
  case 4: return state=="IDLE";
  case 6: return state=="PAUSED";
  case 7: return state=="STARTED" || state == "STOPPED";
  default: return false;
  }
}
于 2013-09-13T18:40:23.167 回答
1

BartoszKP 的带有 STL 集的解决方案可能是最好的简单解决方案。

如果你真的很热衷,你可以用这样的东西来模拟一个穷人的哈希:

const unsigned nIdle('ELDI');    // "IDLE" with byte order reversed
const unsigned nStarted('RATS'); // "STAR" with byte order reversed
const unsigned nStopped('POTS'); // "STOP" with byte order reversed
const unsigned nPaused('SUAP');  // "PAUS" with byte order reversed

bool Verify(const char *szState)
{
    unsigned nState = *reinterpret_cast<const unsigned *>(szState);

    switch (nState)
    {
        case nIdle:
        case nStarted:
        case nStopped:
        case nPaused:
            return true;

        default:
            return false;
    }
}

int main()
{
    const std::string s[] = {"IDLE", "STARTED", "STOPPED", "PAUSED", "INVALID"};
    for (auto itr=std::begin(s); itr!=std::end(s); ++itr)
    {
        std::cout << *itr << '\t';
        if (Verify(itr->c_str()))
            std::cout << "OK";
        else
            std::cout << "Fail";
        std::cout << std::endl;
    }
    return 0;
}

您需要确定您的数据。任何短于 sizeof(unsigned) 的字符串都可能存在风险,您需要确保该字符串的前 4 个字节是唯一的。例如,“STOPPED”和“STOPPING”对于 4 个字节是相同的。

你可以做一个适当的哈希,但这可能不会比比较字符串快。

于 2013-09-13T19:43:10.617 回答
0

是的。

不要使用字符串,使用枚举来表示状态机的内部状态,并在需要时转换为字符串:

namespace State
{
    enum Type
    {
        IDLE, STARTED, STOPPED, PAUSED
    };

    std::string names[] = { "IDLE", "STARTED", "STOPPED", "PAUSED" };
}

然后编译器强制您使用有效状态。然后,您使用名称数组从枚举值中获取字符串以进行其他处理。您甚至可以使用静态断言来确保枚举和字符串的数量匹配。

或者boost::enum,甚至提供了一种机制来创建这种枚举类型,其中包含与字符串的内置转换。

于 2013-09-13T18:33:53.793 回答