char枚举中的值分配不正确

Abh*_*yal 24 c++ enums type-conversion implicit-conversion c++11

我正在使用枚举,并尝试从此页面重现一些示例.最初的例子按预期工作,但是我得到了一些有趣的结果,代码如下:

#include <iostream>

enum num : char {
    zero = '0',
    one = '1',
    two = '2',
    three = '3',
    four = '4',
    five = '5',
    six = '6'
};

int main()
{
    const char two = '2';
    std::cout << two << std::endl;
    std::cout << num::two;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出是:

2
50

我预计两种结果都是相同的,但num::two似乎打印出其他一些值.此值也不会改变(50),所以我假设这不是随机/垃圾值,并且有一些char/int解析正在完成,我不明白?这是ideone链接.

我知道我可以通过这样分配来实现它zero = 0,没有单引号并且它有效.但是,我想知道幕后发生了什么,我怎么能控制通过单引号分配可以打印的非单位数值.

T.C*_*.C. 20

这实际上应该是char现在过载; 遗憾的是,没有任何编制者实施DR 1601.

[conv.prom]/4:

可以将其基础类型固定的无范围枚举类型的prvalue([dcl.enum])转换为其基础类型的prvalue.

这意味着num可以提升到char.

此外,如果可以对其基础类型应用整数提升,则其基础类型固定的无范围枚举类型的prvalue也可以转换为提升的基础类型的prvalue.

所以num也可以提升到int.

相关候选人是:

template <class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
                                        char ch );
template<class charT, class Traits>
basic_ostream<charT, Traits>& basic_ostream<charT, Traits>::operator<<(int);
Run Code Online (Sandbox Code Playgroud)

对于两个候选人,第一个参数是身份转换,第二个参数是促销.双方num要char和num到int有晋升职级.

前DR1601,这些同样好,所以模板/非模板决胜局进来.第一个是功能模板; 第二个是普通成员函数,所以第二个获胜.

DR1601增加了一条规则:

如果两者不同,那么促进其基础类型固定为其基础类型的枚举的转换优于促进提升的基础类型的转换.

这意味着,num到char现在比好num到int,所以第一个重载现在是一个更好的匹配,应选择.

  • @bolov这个更改是针对C++ 11的DR,因此应该是追溯性的. (5认同)

Vla*_*cow 14

根据C++标准(4.5积分促销)

4基础类型固定(7.2)的未作用域枚举类型的prvalue可以转换为其基础类型的prvalue. 此外,如果可以对其基础类型应用整数提升,则其基础类型固定的无范围枚举类型的prvalue也可以转换为提升的基础类型的prvalue.

因此,应用了整数提升,并调用了操作符<<对于int类型的对象.


Chr*_*ckl 10

当你说enum num : char,那么你表达的事实num是在方面的内部实现char,但仍然可以自动转换为一个整数值,这是没有必要char.

正如您引用的页面所示:

未范围的枚举类型的值可以隐式转换为整数类型.

请参阅为什么具有固定基础类型char的枚举值会解析为fct(int)而不是fct(char)?关于C++标准关于整体推广和固定底层类型组合的措辞中的问题的有趣讨论.

在任何情况下,您可以将整个事物想象成具有私有char成员变量和公共int转换运算符的类:

// very similar to your enum:
class num {
private:
    char c;

public:
    num(char c) : c(c) {}
    operator int() const {
        return c;
    }
};

num two { '2' };
std::cout << two; // prints 50
Run Code Online (Sandbox Code Playgroud)

要增加类型安全性并使该std::cout行成为编译错误,只需将其enum转换为enum class:

enum class num : char
Run Code Online (Sandbox Code Playgroud)

这再次类似于class num上面的想象,但没有转换运算符.

当你提供一个numto 的实例时std::cout,那么你是一个客户端,num并且逻辑上不认为输出格式会考虑其内部char实现.

为了获得在输出格式更多的控制,你应该做的,而不是像任何其他自定义类型和超负荷operator<<的std::ostream.例:

#include <iostream>

enum class num : char {
    zero = '0',
    one = '1',
    two = '2',
    three = '3',
    four = '4',
    five = '5',
    six = '6'
};

std::ostream& operator<<(std::ostream& os, num const& n)
{
    switch (n)
    {
        case num::zero: os << "Zero"; break;
        case num::one: os << "One"; break;
        case num::two: os << "Two"; break;
        case num::three: os << "Three"; break;
        // and so on
    }
    return os;
}

int main()
{
    std::cout << num::two; // prints "Two"
}
Run Code Online (Sandbox Code Playgroud)

当然,char枚举实例的具体值现在变得毫无用处,所以你可以完全摆脱它们:

enum class num : char {
    zero,
    one,
    two,
    three,
    four,
    five,
    six
};
Run Code Online (Sandbox Code Playgroud)

这可能会让你觉得奇怪,但请记住,一个代表零到六的通用数字的枚举不是一个现实的用例.


bol*_*lov 7

因为这两个调用两个不同的运算符重载:

  • 第一个调用非成员operator<<for std::ostream和char.这会打印出角色.

  • 第二个示例调用成员operator<<进行int整数提升,如其他答案所述.


Mat*_*son 5

原因是你enum : char的不一样char(这正是我们想要的 - 我们不希望枚举与其他类型相同,即使它们是赋值兼容的 - 我们想要void func(num n)区别对void func(char n),对吧?).

因此,既然enum num不是a char,operator<<(int)将使用,并打印整数值,即使基础类型是char.不完全合理,但我确信这就是发生的事情.