用户定义的C ++ 11枚举类默认构造函数 [英] User Defined C++11 enum class Default Constructor

查看:108
本文介绍了用户定义的C ++ 11枚举类默认构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以指定枚举类的默认构造函数?

Is there a way to specify the default constructor of an enum class?

我正在使用 enum class 来指定库中特定数据类型所允许的一组值:在这种情况下,它是Raspberry Pi的GPIO引脚ID号。看起来像这样:

I am using an enum class to specify a set of values which are allowable for a particular datatype in a library: in this case, it's the GPIO pin id numbers of a Raspberry Pi. It looks something like this:

枚举类PinID:int {N4 = 4,N17 = 17,/ * ... etc ... * /}

我这样做的重点不是仅仅使用例如 int 是为了确保代码是安全的:我可以 static_assert (或以其他方式进行编译时确保-实际使用的方法对我而言并不重要)之类的东西并没有出现拼写错误(通过5而不是4,等等),并且我收到类型不匹配等的自动错误消息。

The point of me doing this instead just of using, say, an int is to ensure that code is safe: I can static_assert (or otherwise compile-time ensure -- the actual method used is not important to me) things like that someone hasn't made a spelling error (passing a 5 instead of a 4, etc), and I get automatic error messages for type mismatches, etc.

那么问题是该 enum类具有一个默认构造函数-为了与C的 enum s兼容,我假定(因为它们具有相同的行为)-初始化为 enum类等效于 0 。在这种情况下,没有 0 值。这意味着用户进行声明/定义,例如:

The problem then is that enum class has a default constructor that -- for compatibility's sake with C's enums I assume (since they have the same behaviour) -- initializes to the enum class equivalent of 0. In this case, there is no 0 value. This means that a user making a declaration/definition like:

PinID pid = PinID();

正在获得未明确定义的枚举器(当人们查看代码时,甚至似乎不存在),并且可能导致运行时错误。这也意味着在没有错误/默认情况的情况下,像 switch 之类的技术无法使用显式定义的枚举器的值,我想避免这种情况,因为它迫使我 throw 或返回类似 boost :: optional 的东西,这些都不太适合静态分析。

is getting an enumerator that isn't explicitly defined (and doesn't even seem to "exist" when one looks at the code), and can lead to runtime errors. This also means that techniques like switching over the values of explicitly defined enumerators is impossible without having an error/default case -- something I want to avoid, since it forces me to either throw or do something like return a boost::optional, which are less amenable to static analysis.

我试图将默认构造函数定义为无济于事。我(拼命地)试图定义一个共享 enum类的名称的函数,但这(并不奇怪)导致了奇怪的编译器错误。我想保留将 enum类强制转换为 int 的功能,而所有 N# 枚举数映射到它们各自的,因此仅定义(例如N4 = 0)是不可接受的;

I tried to define a default constructor to no avail. I (desperately) tried to define a function which shares the name of the enum class, but this (rather unsurprisingly) resulted in strange compiler errors. I want to retain the ability to cast the enum class to int, with all N# enumerators mapping to their respective #, so merely "defining", say, N4 = 0 is unacceptable; this is for simplicity and sanity.

我想我的问题有两方面:有没有办法获得使用<$ c之后的静态安全性? $ c>枚举类?如果没有,一个人更喜欢其他什么可能性?我想要的是什么

I guess my question is two-fold: is there a way to get the kind of static safety I'm after using enum class? If not, what other possibilities would one prefer? What I want is something which:


  1. 是默认构造的

  2. 可以设为默认构造任意有效值

  3. 提供枚举类 es

  4. 提供的一组指定的有限值
  5. 至少具有与 enum类

  6. (最好)不涉及运行时多态性
  7. 相同的类型安全性。
  1. is default constructable
  2. can be made to default construct to an arbitrary valid value
  3. provides the "finite set of specified" values afforded by enum classes
  4. is at least as type safe as an enum class
  5. (preferably) doesn't involve runtime polymorphism

我想要默认可构造性的原因是因为我计划使用 boost :: lexical_cast 来减少 enum类值与实际输出的字符串之间的转换涉及的语法开销系统(在这种情况下为sysfs); boost :: lexical_cast 需要默认的可构造性。

The reason I want default constructability is because I plan to use boost::lexical_cast to reduce the syntactic overhead involved in conversions between the enum class values, and the actual associated strings which I output to the operating system (sysfs in this case); boost::lexical_cast requires default constructability.

我的推理中的错误是受欢迎的-我开始怀疑在这种情况下,枚举类 es是错误工作的正确对象;如果要求,将提供说明。谢谢您的时间。

Errors in my reasoning are welcome -- I am beginning to suspect that enum classes are the right object for the wrong job, in this case; clarification will be offered if asked. Thank you for your time.

推荐答案

使用 enum class 定义的类型或枚举结构不是一个类,而是作用域枚举,并且不能定义默认构造函数。 C ++ 11标准定义了 PinID pid = PinID(); 语句将进行零初始化。其中 PinID 被定义为枚举类。通常,它还允许枚举类型保存除枚举器常量以外的值。

A type defined with enum class or enum struct is not a a class but a scoped enumeration and can not have a default constructor defined. The C++11 standard defines that your PinID pid = PinID(); statement will give a zero-initialization. Where PinID was defined as a enum class. It also allows enum types in general to hold values other than the enumerator constants.

要了解PinID()初始化为零,需要阅读标准段 3.9.9、8.5.5、8.5.7 8.5.10 在一起:

To understand that PinID() gives zero initialization requires reading standard sections 3.9.9, 8.5.5, 8.5.7 and 8.5.10 together:

8.5.10 -一个对象,其初始值设定项是一组空的括号(即())应进行值初始化

8.5.7 -要对类型T的对象进行值初始化意味着: ... 否则,该对象将被零初始化。

8.5.5 -要零初始化类型T的对象或引用意味着:—如果T是标量类型(3.9),将对象设置为值0(零),作为整数常量表达式,转换为T;

3.9。 9 -枚举类型是称为标量类型的类型集合的一部分。

3.9.9 - States that enumeration types are part of the set of types known as scalar types.

可能的解决方案:

要达到1到5分,您可以按照以下方式编写课程:

To meet your points 1 to 5 you could write a class along the lines of:

class PinID
{
private:
    PinID(int val)
    : m_value(val)
    {}

    int m_value;

public:
    static const PinID N4;
    static const PinID N17;
    /* ...etc... */ 

    PinID() 
    : m_value(N4.getValue())
    {}

    PinID(const PinID &id)
    : m_value(id.getValue())
    {}

    PinID &operator = (const PinID &rhs)
    {
        m_value = rhs.getValue();
        return *this;
    }

    int getValue() const
    {
        return m_value;
    }

    // Attempts to create from int and throw on failure.
    static PinID createFromInt(int i);

    friend std::istream& operator>>(std::istream &is, PinID &v)
    {
        int candidateVal(0);
        is >> candidateVal;
        v = PinID::createFromInt(candidateVal);
        return is;
    }
};

const PinID PinID::N4 = PinID(4);
/* ...etc... */

那可以给你一些东西您将需要做出特定的努力才能将无效值引入其中。默认的构造函数和流运算符应允许它与lexical_cast一起使用。

That can give you something that you would have to make specific efforts to get an invalid values into. The default constructor and stream operator should allow it to work with lexical_cast.

似乎这取决于PinID创建后对它的操作有多重要,是否值得编写一个类或一个类。只是在使用值的任何地方都处理无效值。

Seems it depends how critical the operations on a PinID are after it's creation whether it's worth writing a class or just handling the invalid values everywhere as the value is used.

这篇关于用户定义的C ++ 11枚举类默认构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆