使用带值传递和函数返回的枚举的正确方法?

时间:2011-02-05 15:34:53

标签: c++ enums namespaces struct c++11

我理解问题标题非常模糊,因此正文:)

我有几个enum用于识别文件类型和其他需要轻松区分的东西。我以前的做法是:

namespace my_namespace
{
    namespace fileType
    {
        enum fileType
        {
            SOURCE,
            HEADER,
            RESOURCE
        };
    }
}
using namespace my_namespace::fileType;

这让我可以定义一个函数:

fileType someFunction( const std::string &someFile, const fileType someType )
{
    //...
    return fileType::HEADER;
}

我可以定义和比较这样的变量:

fileType type = fileType::SOURCE;

哪个太棒了。虽然有一些警告。标题(没有任何using指令)需要加倍预期的枚举名称,让编译器知道你使用的是类型,而不是命名空间:

my_namespace::fileType::fileType soeFunction( const std::string &someFile, const my_namespace::fileType::fileType someType );

哪个看起来很傻,难以阅读并且难以理解。此外,MSVC在警告级别1处抱怨使用的非标准扩展(由于示例中的doule fileType)。奇怪的是,海湾合作委员会并没有在最严格的环境下抱怨,但嘿,这是一个不同的故事。

我现在想要以一种(匿名)方式重写我的enum s在结构而不是命名空间中,允许在声明函数时进行单一限定,从而关闭MSVC的警告。但是在这种情况下如何编写return语句。是否绝对有必要提供一个构造函数/转换操作符,或者有没有办法解决这个问题?

示例:

// enum definition
namespace my_namespace
{
    struct fileType
    {
        enum
        {
            SOURCE,
            HEADER,
            RESOURCE
        };
    }
}
using my_namespace::fileType;

// function declaration in header
my_namespace::fileType someFunction( const std::string &s, const my_namespace::fileType type );

// function implementation in .cpp file
using my_namespace::fileType;

fileType someFunction( const string &s, const fileType type )
{
    //...(problem is situated below)
    return fileType::SOURCE;
}

这说明了我想做的事情。我想避免明确地调用enum struct的构造函数:fileType(fileType::SOURCE)这会让我使用双fileType

感谢您的帮助!

PS:如果之前已经回答过这个问题,我很抱歉,但是我没有找到谷歌或之前关于这个主题的问题的好选择。

3 个答案:

答案 0 :(得分:10)

我个人使用一个非常简单的技巧:

struct EnumName
{
  enum type {
    MemberOne,
    MemberTwo,
    ...
  };
};

typedef EnumName::type EnumName_t;

// Usage
EnumName_t foo = EnumName::MemberOne;

在C ++ 0x中,您可以直接使用范围的枚举器:

enum struct EnunName // note: struct and class equivalent here
{
  MemberOne,
  MemberTwo,
  ...
};

// Usage
EnumName foo = EnumName::MemberOne;

哪个真的很棒:)。

注意:scoped enum也不受整体推广的影响,这真的很棒

答案 1 :(得分:0)

从我的角度来看,如果命名空间或结构不包含任何内容,只有单个枚举已经证明了命名空间/结构是无用的。因此你应该简单地放弃它。

你应该试试

namespace my_namespace
{
    enum fileType
    {
        SOURCE,
        HEADER,
        RESOURCE
    };
}

更适合你。通常情况下,在这种情况下,程序员喜欢在实际的枚举值前加上枚举的名称,从而导致

namespace my_namespace
{
    enum fileType
    {
        FILE_TYPE_SOURCE,
        FILE_TYPE_HEADER,
        FILE_TYPE_RESOURCE
    };
}

在这里你甚至可以选择将enum本身重命名为

    enum FILE_TYPE
    { ...

此外,枚举更适用于本身不完整且将来永远不会扩展的值组,例如:工作日的枚举。
如果你认为enum fileType可能永远不完整(因为那里有数百种文件类型)你可能想采取另一种方法 - 使用常量组。使用常量组优于枚举,如果扩展该常量组,则只需重新编译使用新添加值的模块/文件,而如果向枚举添加值,则可能需要重新编译使用的所有源那个枚举。

常数组可能如下所示:

namespace nms
{
    typedef const unsigned short fileType_t;
    namespace fileType
    {
        fileType_t SOURCE   = 1;
        fileType_t HEADRE   = 2;
        fileType_t RESOURCE = 3;
    }
}

当然,如果您愿意,可以将typedef语句移动到fileType命名空间中或完全删除它,并在任何地方直接使用“const unsigned short”。

由于我家里没有编译器,上面的代码可能无法从头开始编译。但我相信你会明白这一点。

使用这种方法,您的源代码应如下所示:

using nms;

nms::fileType_t someFunction( const string &s, const nms::fileType_t type )
{
    return nms::fileType::SOURCE;
}

答案 2 :(得分:0)

是的,如果您希望同一范围内的不同枚举具有“最后”成员,则无法完成。在这种情况下,您需要在枚举名称前加上“last”值(例如,类似于第二个枚举示例。

关于参数检查的“最后”条目,我可能错过了你的观点。例如,如果您将枚举作为参数传递给函数,例如

void f( enum fileType type )  

与fileType没有'last'元素相比,它没有提供更多'类型安全'。

我可以看到最后一个元素(然后也是第一个元素!)的唯一原因是你想要在循环中迭代枚举元素的元素。例如:

enum E
{
    first,
    e1 = first,
    e2,
    e3,
    last
}  

for (int i = first; i < last; ++i)
    ...  

如果是这样的话,那么想要让两个不同的枚举列出相同名称的'last'元素是不是很人为?在两个不同的枚举中有一个“最后”的优势在哪里? 与例如相比,它是否提高了可读性有E_last和F_last?
或者它是否有助于保存甚至一行代码的写作? 在scoped枚举中使用'last'的原因是什么?默认情况下,Scoped枚举不会转换为int。 (但也许我误解了你想做的事情......)

关于“你不能保持枚举值的简短......”我担心我没有得到你想说的话。是不是我在常量组示例中使用'const unsigned short'?

也不要误解我的意思(想要处理文件类型)我主张使用常量组。使用它们,在不同的组中使用相同的“第一个”和“最后一个”成员(但具有不同的值)是很容易和自然的。见

namespace nms
{
    typedef const unsigned short G1_t
    namespace G1
    {
        G1_t  first = 1;
        G1_t  type1 = 1;
        G1_t  type2 = 2;
        G1_t  type3 = 3;
        G1_t  last  = 3;
    }

    typedef const long G2_t
    namespace G2
    {
        G1_t  first = -1;
        G1_t  obj1  = -1;
        G1_t  obj2  =  0;
        G1_t  obj3  =  1;
        G1_t  last  =  1;
    }
}

至于'namespace - namespace - enum',我不喜欢额外的间接而没有实质性的好处。至于'namespace - struct / class - enum',这更具哲学性:

可以这么说,C是一种光滑而快速的摩托车,这使得编写汇编代码几乎没有必要。这也是C cast操作符所拥有的,它允许完全降低类型安全性并按照您的方式执行您想要的操作。

C ++仍然喜欢成为C的超级集合。它增加了类和面向对象的编程,但仍然希望保留摩托车。哪个好。现在添加更多'类型安全'范围的枚举,同时仍然保持演员操作员看起来像是想要为摩托车添加安全气囊和安全带。

我并不反对修改枚举以获得更好的枚举(如果真的需要),但如果有人这样做,也应该偶尔(例如每5年)放弃现在被认为是旧的,过时的和邪恶的东西。否则,语言会变得越来越混乱,初学者也越来越难学。并且像每种工具编程语言都需要易于使用,并且包括没有十几种方法来做同样的事情。