Java C++ 中的样式枚举 类

Java Style Enum Classes in C++

我正在尝试为类似于 Java 枚举的数据类型实现枚举 class。

DataType.h:

namespace Galactose {
    class DataType {
    public:
        DataType(const std::string& a_name, const size_t a_byteSize);
        DataType(const std::string& a_name, const DataType& a_componentType, const uint32_t a_componentCount);

    private:
        inline static std::vector<DataType> s_types;

        int32_t m_ordinal;
        std::string m_name;
        size_t m_byteSize;
        const DataType& m_componentType;
        uint32_t m_componentCount;
    };

    namespace DataTypes {
        inline static const DataType FLOAT(GT_STRINGIFY(FLOAT), sizeof(float));
        inline static const DataType VECTOR2(GT_STRINGIFY(VECTOR2), FLOAT, 2);
        inline static const DataType VECTOR3(GT_STRINGIFY(VECTOR3), FLOAT, 3);
        inline static const DataType VECTOR4(GT_STRINGIFY(VECTOR4), FLOAT, 4);
    };
}

DataType.cpp:

#include "DataType.h"

namespace Galactose {
    DataType::DataType(const std::string& a_name, const size_t a_byteSize)
        : m_ordinal(int32_t(s_types.size())),
          m_name(a_name),
          m_byteSize(a_byteSize),
          m_componentType(*this),
          m_componentCount(1)
    {
        s_types.emplace_back(*this);
    }

    DataType::DataType(const std::string& a_name, const DataType& a_componentType, const uint32_t a_componentCount)
        : m_ordinal(int32_t(s_types.size())),
          m_name(a_name),
          m_byteSize(a_componentType.m_byteSize * a_componentCount),
          m_componentType(a_componentType),
          m_componentCount(a_componentCount)
    {
        s_types.emplace_back(*this);
    }
}

GT_STRINGIFY 在这样的预编译头文件中定义:

#define GT_STRINGIFY(x) #x

问题是 DataTypes 中的变量被多次实例化。可能每个 #include "DataType.h" 一次。我希望它们只被实例化一次。

我试图将 DataTypes namespace 更改为 class,但在每个 GT_STRINGIFY 处给出 Error C2059 syntax error: 'string'

我知道我可以检查 name 是否已经存在,或者使用 set 而不是 vector。但是我真的不想走这条路。

感谢您的宝贵时间。欢迎任何建议。

使用其他语言 tools/techniques 通常不是前进的方向,因此我向您推荐 enum class(它是特定于 C++ 的,可能是您将获得的最接近的内置内容)。 Why is enum class preferred over plain enum?

另外需要注意的是你需要头部防护: Header guards in C++ and C 基本上是这样的:

#ifndef HEADER_NAME_HPP
#define HEADER_NAME_HPP
//code
#endif

static 在命名空间范围内的一个变量上意味着这个变量在使用这个 header 的每个翻译单元(.cpp 文件)中存在一次。确保所有翻译单元共享相同 object 的方法是将这些变量声明为 extern 并在 DataType.cpp.

中定义它们

DataType.h:

...
    namespace DataTypes {
        extern const DataType FLOAT;
        extern const DataType VECTOR2;
        extern const DataType VECTOR3;
        extern const DataType VECTOR4;
    };
...

DataType.cpp:

...

    namespace DataTypes {
        const DataType FLOAT("FLOAT", sizeof(float));
        const DataType VECTOR2("VECTOR2", FLOAT, 2);
        const DataType VECTOR3("VECTOR3", FLOAT, 3);
        const DataType VECTOR4("VECTOR4", FLOAT, 4);
    };
...

为了更接近 java 枚举,您可能希望在 DataType 中将符号声明为静态变量,而不是允许您通过例如引用它们Galactose::DataType::FLOAT.

...
class DataType {
    public:
        DataType(const std::string& a_name, const size_t a_byteSize);
        DataType(const std::string& a_name, const DataType& a_componentType, const uint32_t a_componentCount);

        static const DataType FLOAT;
        static const DataType VECTOR2;
        static const DataType VECTOR3;
        static const DataType VECTOR4;

    private:
        ...
    };
...

DataType.cpp:

...
    const DataType DataType::FLOAT("FLOAT", sizeof(float));
    const DataType DataType::VECTOR2("VECTOR2", FLOAT, 2);
    const DataType DataType::VECTOR3("VECTOR3", FLOAT, 3);
    const DataType DataType::VECTOR4("VECTOR4", FLOAT, 4);
...

您当然可以使用包含静态成员的单独 class,但这与 java 不同,其中枚举常量可通过枚举类型访问。


我在这个回答中假设您的 header 文件没有完整发布。否则你应该添加 header 守卫以避免在通过多个其他 header 间接包含此文件时出现问题;此外,您应该为所有使用的类型添加包含。 header 中将缺少以下内容:

#include <string>
#include <vector>