【问题标题】:Creating a struct as enum class member创建一个结构作为枚举类成员
【发布时间】:2019-12-18 15:01:52
【问题描述】:

我正在为图书馆创建一个多级枚举。

  • 我想要这样的东西(不一定完全一样)
Book::Category::PROGRAMMING::C_PLUS_PLUS

其中BookstructCategory 是(当前)enum class
基本上,我想嵌套枚举

我知道我能做到:

Book::Category::PROGRAMMING_C_PLUS_PLUS

但这不仅会在Category 中创建一个 值列表,而且会使维护它成为一场噩梦(我试图用 30 来做这件事,但已经很头疼了)。

我想分而治之。

编辑 1:我不希望它成为 std::string 的原因是它的值可以是任何东西。我想限制Category 的域。

不,PROGRAMMING 不是我图书馆的主要部分。让我尝试使用类和继承。

基本上,我想要enums 的原因是拥有一组固定的有效常量。


参考资料:

【问题讨论】:

  • 强迫它们固定不变,无论如何你都在强迫自己陷入“头痛”的境地。您强迫自己维护一个有效枚举的恒定列表,这些枚举在某些时候可能会更改,此时您将不得不更新您的枚举列表并重新编译您的代码.一个可延展的解决方案是允许它们成为字符串,并在启动时读取 .txt 文件或其他内容,并将其作为可接受值的列表,如果需要验证,可以检查这些值。
  • @alteredinstance 另一个非常有效的观点!我认为这应该有效。程序应该有代码,而不是数据库。这属于一个单独的专用文件。请添加到答案中! +1
  • 很高兴我能提供帮助!让我知道这对您是如何工作的,希望实施起来不会走太多弯路。我认为“程序应该有代码,而不是数据库”是理解解决方案的好方法。

标签: c++ enums


【解决方案1】:

您不能嵌套enums,但是,您可以这样做:

struct Book {
    struct Category {
        enum class PROGRAMMING {
            // ...
        };
        enum class COOKING {
            // ...
        }; 
    };
};

类似于在链接问题中使用命名空间,但由于它在一个类中并且你不能这样做,你可以使用另一个结构。

【讨论】:

  • 好的。这看起来很整洁。因此,基本上将所有 n-1 级设为struct,最后一级设为真正的enum class。仍然必须小心妥善管理它。
  • 如果你不能为上层使用命名空间,那么可以。
  • 好的,快速提问。如果我必须存储一个类别,可能是 PROGRAMMING 相关或 COOKING 相关,该怎么办?
  • 那你就有问题了 ;) 你可以在每个enum 中输入相同的名称,但它们会完全分开...
【解决方案2】:

您可以这样做,但这将是一个糟糕的设计

一个常见的代码味道是使用 enum 来表示显然应该是一个类 - 这里的情况是您希望 C_PLUS_PLUS 类型是 PROGRAMMING 类别的派生。

然而,enums 最适合用于描述可能的状态,并且无法通过设计继承,正如您在参考文献之一中所指出的那样。在我看来,最好的做法是在Category 中创建两个独立的成员变量,它们可以保存值,例如PROGRAMMINGC_PLUS_PLUS,并取消它们作为@ 的状态987654328@s。

想一想:什么最能封装开放式领域,例如书籍流派/子流派?您是否打算使用enum每一种可能性进行编程?还是只使用两个strings(例如genresubgenre)更适合这样的开放式字段?

或者,也许,如果您专门将 PROGRAMMING 书籍作为您设计的主要部分,请将 PROGRAMMING 转换为一个类,并将 C_PLUS_PLUS 作为 enum 内的一部分 /em> 类。但是不要让他们都成为enums - 这只是在寻求问题,并不能解决您已经描述的维护问题。

编辑:从我所做的评论中添加 -

强迫它们固定不变,无论如何你都在强迫自己陷入“头痛”的境地。您强迫自己维护一个可能在某些时候更改的有效枚举的恒定列表,此时您将不得不更新您的枚举列表并重新编译您的代码。一个可延展的解决方案是允许它们成为字符串,并在启动时读取 .txt 文件或其他内容,并将其作为可接受值的列表,如果需要验证,可以检查这些值。

【讨论】:

  • 查看我的实现。 :-) 再次感谢!欢迎提出任何建议!
【解决方案3】:

应答复者的要求,我将发布我的实现以供将来参考。
这是Book

struct Book
{
    // A Map of categories and its list of sub-categories
    static std::map< std::string, std::vector< std::string > > Categories;

    // default parameter for unit testing, 
    // thanks to https://stackoverflow.com/questions/40297782/c-unit-testing-check-output-is-correct/59374648#59374648
    static void initBookCategories(std::string file_name = "categories.txt")
    {
        // Open the file in read mode
        std::ifstream allowed_categories(file_name);

        // Check if file open is unsuccessful
        if(!allowed_categories)
        {
            // Signal error and exit
            std::cerr << "\n\nFile Not Found!\nError Initialising DB! Exiting...";
            return;
        }

        // Read the category_name
        std::string category_name;
        // Until there are categories left
        while(std::getline(allowed_categories, category_name))
        {
            // Read the whole sub-category list
            std::string subcategory_names;
            // Untill end of line
            std::getline(allowed_categories, subcategory_names);
            // Convert to std::stringstream for parsing
            std::istringstream parse_subcategories(subcategory_names);
            // Skip the empty line
            allowed_categories.ignore();

            // Now read the sub-categories
            // Need a std::vector to store the list of subcategory names
            std::vector< std::string > subcategory_list;
            // Reusing subcategory_names for each subcategory_name
            while(parse_subcategories >> subcategory_names)
            {
                // Add to the list of sub-categories
                subcategory_list.push_back(subcategory_names);
            }

            // Add this newly read category with its list of subcategories our map
            Categories.insert(std::pair< std::string, std::vector< std::string > >(category_name, subcategory_list));
        }
    }
    static void getCategoryList()
    {
        // For each category
        for(std::pair< const std::string, std::vector< std::string > >& category : Categories)
        {
            // List the sub-categories
            int index = 0;
            // Print the category name
            std::cout << " " << category.first << ":\n";
            // Loop over the sub-categories
            for(std::string& subcategory_name : category.second)
            {
                // Printing each sub-category in a line
                std::cout << "   " << ++index << ") " << subcategory_name << "\n";
            }
        }
    }
};
std::map< std::string, std::vector< std::string > > Book::Categories;

我们的主要功能使用这个:

int main()
{
    Book::initBookCategories();
    Book::getCategoryList();
    return 0;
}

最后但同样重要的是categories.txt的格式:

PROGRAMMING
C_PLUS_PLUS C PYTHON JAVA SQL

MATHEMATICS
CALCULUS ALGEBRA DISCRETE

BIOLOGY
ZOOLOGY BOTANY MICROBIOLOGY BIOTECHNOLOGY

CHEMISTRY
ORGANIC INORGANIC PHYSICAL

SOCIAL_STUDIES
POLITICAL_SCIENCE GEOGRAPHY HISTORY CIVIL_SCIENCE

BUSINESS_ADMINISTRATION
ACCOUNTS MANAGEMENT STATISTICS ECONOMICS

SCIENCE_FICTION
SPACE ALIENS FUTURE WAR ADVENTURE

LITERATURE
ENGLISH HINDI COMEDY NOVEL

PHYSICS
MECHANICS FLUIDS NUCLEAR THERMODYNAMICS

ARTS_AND_HUMANITIES
PHILOSOPHY SOCIOLOGY PSYCHOLOGY ANTHROPOLOGY

谢谢!

【讨论】:

  • 看起来很棒!直观且易于动态扩展 - 不错的解决方案 :)
猜你喜欢
  • 2021-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-02
  • 1970-01-01
  • 1970-01-01
  • 2014-08-05
相关资源
最近更新 更多