2

简短版本:无论如何在类中嵌套函数,enum以便EnumClass::EnumLabel您可以拥有有用的相关函数,例如EnumClass::to_string(EnumClass value)而不是拥有全局函数EnumClass_to_string(EnumClass value)

长版:所以我在玩 OpenGL,它带有一堆整数#defines,用于 GPU 上的各种功能。为了 C 兼容性,这些定义在其标签之外没有真正的结构,因此很容易使用不正确的定义。为了帮助纠正这个新手错误的来源,我一直在将相关定义分组到enum类中,如下面的调试消息源示例:

enum class Source {
    API = GL_DEBUG_SOURCE_API,
    WINDOW_SYSTEM = GL_DEBUG_SOURCE_WINDOW_SYSTEM,
    SHADER_COMPILER = GL_DEBUG_SOURCE_SHADER_COMPILER,
    THIRD_PARTY = GL_DEBUG_SOURCE_THIRD_PARTY,
    APPLICATION = GL_DEBUG_SOURCE_APPLICATION,
    OTHER = GL_DEBUG_SOURCE_OTHER
};

由于这些通常用于调试输出,因此我决定创建一个to_string函数来简化将它们的含义输出到日志文件。

std::string source_to_string(KHR_debug::Source source) {
    if(source == KHR_debug::Source::API) {
        return "GL_DEBUG_SOURCE_API";
    } else if(source == KHR_debug::Source::WINDOW_SYSTEM) { 
        return "GL_DEBUG_SOURCE_WINDOW_SYSTEM";
    } else if(source == KHR_debug::Source::SHADER_COMPILER) {
        return "GL_DEBUG_SOURCE_SHADER_COMPILER";
    } else if(source == KHR_debug::Source::THIRD_PARTY) {
        return "GL_DEBUG_SOURCE_THIRD_PARTY";
    } else if(source == KHR_debug::Source::APPLICATION) {
        return "GL_DEBUG_SOURCE_APPLICATION";
    } else if(source == KHR_debug::Source::OTHER) {
        return "GL_DEBUG_SOURCE_OTHER";
    } else {
        return "INVALID_SOURCE_ENUM";
    }
}

但是,我认为如果我可以将辅助函数嵌套在enum类本身中会更整洁。这样source_to_string(source)您就可以使用Source::to_string(source). 我很欣赏这个功能,如果你使用旧式enum类,你只需将你的类包装enum在一个类/结构中,但是我使用 C++11enum类的原因之一是因为它们增加了类型安全性。

我尝试在类旁边有一个类/命名空间,enum但这似乎覆盖了现有定义之一。

4

3 回答 3

10

这里的惯用方法是使用自由函数:就像你会做的那样

using std::to_string;

int ltuae = 42;
std::cout << "The answer: " << to_string(ltuae) << std::endl;

你可以做

KHR_debug::Source s /* = ... */;
std::cout << "The source: " << to_string(s) << std::endl;

注意 正如所写,这使用了 C++ 的“隐藏”特性:参数依赖查找。写作to_string会发现KHR_debug::to_string,因为该命名空间包含参数类型。

在 Coliru 上看到它

完整样本

#include <iostream>
#include <string>
namespace KHR_debug
{

    enum class Source {
        API             /*= GL_DEBUG_SOURCE_API            */,
        WINDOW_SYSTEM   /*= GL_DEBUG_SOURCE_WINDOW_SYSTEM  */,
        SHADER_COMPILER /*= GL_DEBUG_SOURCE_SHADER_COMPILER*/,
        THIRD_PARTY     /*= GL_DEBUG_SOURCE_THIRD_PARTY    */,
        APPLICATION     /*= GL_DEBUG_SOURCE_APPLICATION    */,
        OTHER           /*= GL_DEBUG_SOURCE_OTHER          */
    };

    std::string to_string(Source source) {
        switch(source) {
            case Source::API:             return "GL_DEBUG_SOURCE_API";
            case Source::WINDOW_SYSTEM:   return "GL_DEBUG_SOURCE_WINDOW_SYSTEM";
            case Source::SHADER_COMPILER: return "GL_DEBUG_SOURCE_SHADER_COMPILER";
            case Source::THIRD_PARTY:     return "GL_DEBUG_SOURCE_THIRD_PARTY";
            case Source::APPLICATION:     return "GL_DEBUG_SOURCE_APPLICATION";
            case Source::OTHER:           return "GL_DEBUG_SOURCE_OTHER";
            default:                      return "INVALID_SOURCE_ENUM";
        }
    }
}

int main()
{
    using std::to_string;

    int ltuae = 42;
    std::cout << "The answer: " << to_string(ltuae) << std::endl;

    KHR_debug::Source s = KHR_debug::Source::APPLICATION;
    std::cout << "The source: " << to_string(s) << std::endl;
}

请注意我如何巧妙地更改您的to_string方法以使用switch它应该使用的地方:)

于 2013-08-20T23:28:34.363 回答
2

这是直接不可能的。

enum只能声明一个: access enum class enumeration-identifier [:underlying-type] { enumerator-list } [var];。它们只能包含enumerator-list

但也许你可以使用 Wrapper struct

#include <string>
#include <iostream>

struct SourceWrapper
{
    enum Source {
        API = 0,
        WINDOW_SYSTEM = 1,
        SHADER_COMPILER = 2,
        THIRD_PARTY = 3,
        APPLICATION = 4,
        OTHER = 5,
    };

    static std::string ToString( Source source ) {
        if(source == Source::API) {
            return "GL_DEBUG_SOURCE_API";
        } else if(source == Source::WINDOW_SYSTEM) {
            return "GL_DEBUG_SOURCE_WINDOW_SYSTEM";
        } else if(source == Source::SHADER_COMPILER) {
            return "GL_DEBUG_SOURCE_SHADER_COMPILER";
        } else if(source == Source::THIRD_PARTY) {
            return "GL_DEBUG_SOURCE_THIRD_PARTY";
        } else if(source == Source::APPLICATION) {
            return "GL_DEBUG_SOURCE_APPLICATION";
        } else if(source == Source::OTHER) {
            return "GL_DEBUG_SOURCE_OTHER";
        } else {
            return "INVALID_SOURCE_ENUM";
        }
    }
};

PS:出于测试目的,我删除了你的 GL 宏。

活生生的例子

于 2013-08-20T21:26:16.343 回答
1

您的另一个选择是enum完全废弃 s 并使用稍微复杂的类型。这在语法上不太友好,但它允许您将方法放在enum“实例”(实际上是静态常量)上。

// Source.h
#include <string>

class Source
{
private:
    const int value;
    const std::string name;

    Source(const int value, const std::string name)
        : value(value), name(name) { }

public:
    inline std::string ToString() const { return this->name; }

    inline bool operator==(const Source &that) const
    {
        return this->value == that.value;
    }

    inline bool operator!=(const Source &that) const
    {
        return !(*this == that);
    }

    static const Source Api;
    static const Source WindowSystem;
    static const Source ShaderCompiler;
    static const Source ThirdParty;
    static const Source Application;
    static const Source Other;
};

// Source.cpp
const Source Source::Api = Source(0, "GL_DEBUG_SOURCE_API");
const Source Source::WindowSystem = Source(1, "GL_DEBUG_SOURCE_WINDOW_SYSTEM");
const Source Source::ShaderCompiler = Source(2, "GL_DEBUG_SOURCE_SHADER_COMPILER");
const Source Source::ThirdParty = Source(3, "GL_DEBUG_SOURCE_THIRD_PARTY");
const Source Source::Application = Source(4, "GL_DEBUG_SOURCE_APPLICATION");
const Source Source::Other = Source(5, "GL_DEBUG_SOURCE_OTHER");

这允许像

Source firstSource = GetSourceFromSomewhere();
Source secondSource = GetSourceFromElsewhere();

if (firstSource != secondSource)
{
    std::cerr << "Sources are not equal: " << firstSource.ToString()
              << " and: " << secondSource.ToString();
}
else if (firstSource == Source::Other)
{
    std::cerr << "First source cannot be Other";
}
于 2013-08-20T23:22:14.683 回答