【问题标题】:How to cleanly create typesafe enum argument如何干净地创建类型安全的枚举参数
【发布时间】:2016-06-08 20:17:25
【问题描述】:

我想创建一个函数“void set_tic_tac_toe_start_player(char c)”。这不是函数的实际名称,但它解释了它的意图。

之所以要在编译时完成,是因为我想创建一个类来封装井字游戏系统,这样系统就可以在游戏开始前显式覆盖start player,而无需重新构建类。

这是一个简单复杂的示例代码。

#include <iostream>
#include <cstdlib>

class TTCSystem
{
public:
    static const int PLAYERX = 1;
    static const int PLAYERO = 2;

    void set_tic_tac_toe_start_player(char c);
private:
    int start_player;    
};

void TTCSystem::set_tic_tac_toe_start_player(char c)
{
    if (c == 'x' || c == 'X') {
        this->start_player = PLAYERX;
    } else if (c == 'o' || c == 'O') {
        this->start_player = PLAYERO;
    } else {
        std::cout << "PANICING AS HARD AS I CAN" << std::endl;
        exit(0);
    }
}

int main(int argc, char **argv)
{
    TTCSystem ttcs;
    ttcs.set_tic_tac_toe_start_player('9');

    return 0;
}

该函数用于覆盖默认进入井字游戏的玩家'X'或'O'。

问题是任何字符都可以通过,而只想接受 {'x', 'X', 'o', 'O'}。

我可以创建一个枚举,但恐怕枚举不会强制进行类型检查。

我可以使用一个类来发明一个枚举类型,或者利用继承,但即使我走这条路,我也不想重新发明轮子并在这方面做得很糟糕。

是否有更通用/优雅/简单的解决方案来创建类型安全的枚举?

我正在寻找能够确保在编译时检查 set_tic_tac_toe_start_player 的输入以确保选择首先进入的玩家是有效玩家(4 个输入之一)。

[编辑]感谢乔纳森的建议,我已经在下面发布了解决方案。

【问题讨论】:

  • 为什么要在编译时检查?你从不在运行时使用这个函数?
  • 你说得有道理。我可以将其设置为常量,我只是想要一个干净的程序员的覆盖。让我重新表述一下这个问题。
  • 我添加了一个简单的小代码来展示我想要做什么的总体思路。这不是最干净的独立演示,但我认为它有点道理。 @Shumush 我在编译时检查,以便我提供一个简单的程序员界面来操作井字游戏系统,而无需重建类。
  • class TTCSystem { enum Player { PlayerX, PlayerY }; void set_tic_tac_toe_start_player(Player p) { start_player = p; } ... }; 有什么问题?枚举类型的唯一有效值是 PlayerXPlayerY(即 0 和 1)。任何其他值都超出了该类型的值范围。在任何情况下,您都可以使用if (start_player == PlayerX) ... else ...,以便将任何非零值视为PlayerY
  • 如果你想要类型安全的枚举,为什么不使用类型安全的枚举?

标签: c++ type-safety


【解决方案1】:

谢谢乔纳森。这是我根据您的回复提出的解决方案。

这部分只是为了演示拒绝无效参数,删除它以查看它是否正确编译。

    ttcs.set_tic_tac_toe_start_player(9);
    std::cout << "player: " 
              << ttcs.get_tic_tac_toe_start_player() 
              << std::endl;

下面是解决办法

#include <iostream>

class TTCSystem
{
public:
    enum Player {PlayerX, PlayerO};

    void set_tic_tac_toe_start_player(Player p);
    char get_tic_tac_toe_start_player();

private:
    Player start_player;    
};

void TTCSystem::set_tic_tac_toe_start_player(Player p)
{
    this->start_player = p;
}

char TTCSystem::get_tic_tac_toe_start_player()
{
    return ((start_player == PlayerX) ? 'X' : 'O');
}


int main(int argc, char **argv)
{
    TTCSystem ttcs;
    ttcs.set_tic_tac_toe_start_player(TTCSystem::PlayerX);
    std::cout << "player: " 
              << ttcs.get_tic_tac_toe_start_player() 
              << std::endl;

    ttcs.set_tic_tac_toe_start_player(TTCSystem::PlayerO);
    std::cout << "player: " 
              << ttcs.get_tic_tac_toe_start_player() 
              << std::endl;

    ttcs.set_tic_tac_toe_start_player(TTCSystem::PlayerX);
    std::cout << "player: " 
              << ttcs.get_tic_tac_toe_start_player() 
              << std::endl;

    ttcs.set_tic_tac_toe_start_player(9);
    std::cout << "player: " 
              << ttcs.get_tic_tac_toe_start_player() 
              << std::endl;

    return 0;
}

【讨论】:

    猜你喜欢
    • 2017-08-19
    • 1970-01-01
    • 2010-09-18
    • 2020-01-04
    • 1970-01-01
    • 2010-09-07
    • 2015-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多