将枚举传递给整体类型的论点

发布于 2025-01-21 05:06:52 字数 1010 浏览 3 评论 0 原文

考虑以下代码:

enum ABC : char
{
    a, b, c
};

void ff(char c)
{
    cout << "char\n";
}

void ff(int i)
{
    cout << "int\n";
}

int main()
{
    ff(a);  // char
}

我可以问为什么要匹配 ff(char)而不是 ff(int)


当我阅读 c ++底漆(第5版)时,我提出了这个问题。在第835页上,作家说:

...我们可以将未枚举的对象或枚举者传递给积分类型的参数。当我们这样做时, enum 值将促进 int 或更大的积分类型...无论其基础类型,对象和枚举者... int

我对上述报价的理解是,当传递给期望积分参数的函数时,枚举者将首先将“至少”“至少”施加到 int 中。因此,我希望上述代码可以调用 ff(int)。实际上,即使是我的Visual Studio编辑器也表明:(对不起,我知道我们应该避免在这里屏幕截图,但我只想显示我所看到的内容)

我也注意到,如果我不明确指定> 的基础类型ABC ,然后将调用 ff(int)

因此,我当前的猜测是这样的:如果我们没有明确指定基础类型,则将传递给积分参数传递给积分参数的对象/枚举器将首先将其施加到 int 中。但是,如果明确指定了基础类型,则编译器将首先尝试匹配期望指定类型的过载函数。

我可以问我的猜测是否正确吗?

Consider the following code:

enum ABC : char
{
    a, b, c
};

void ff(char c)
{
    cout << "char\n";
}

void ff(int i)
{
    cout << "int\n";
}

int main()
{
    ff(a);  // char
}

May I ask why complier matches ff(char) instead of ff(int)?


I came up with this question when I was reading C++ Primer (5th Edition). On page 835, the writers state:

... we can pass an object or enumerator of an unscoped enumeration to a parameter of integral type. When we do so, the enum value promotes to int or to a larger integral type ... Regardless of its underlying type, objects and the enumerators ... are promoted to int.

My understanding to the above quote is that, when being passed to a function expecting an integral argument, an enumerator will first be casted "at least" into an int. So, I'm expecting the above code to call ff(int). Actually, even my Visual Studio editor is showing that: (Sorry I know that we should avoid having screenshot here but I just want to show what I saw)

I also noticed that if I don't explicitly specify the underlying type for ABC, then ff(int) will be called.

So my current guess goes like this: If we don't explicitly specify the underlying type, then the object/enumerator passed to the integral parameter will first be casted into an int. But if the underlying type is explicitly specified, then the compiler will first try to match the overloaded function which expects the specified type.

May I ask if my guess is correct?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

岁月打碎记忆 2025-01-28 05:06:52

我可以问为什么要配合的匹配ff(char)而不是ff(int)?

因为具有固定基础类型的枚举可以隐式转换为其基础类型。基础类型为 char ,因此转换为 char 是最喜欢的候选人过载。

所以我当前的猜测是这样的:如果我们不明确指定基础类型,则将对象/枚举器传递给积分参数,将首先施加到int。

演员是明确的转换。此示例中的转换是隐式的。

确切的首选转换取决于枚举的值。语言规则有点复杂,因此我将从标准中逐字复制:

[cons.prom]

未固定基础类型的未枚举类型的贵族可以转换为以下以下第一种类型的prvalue,可以代表枚举的所有值([dcl.enum]):int,int,无签名的int int int ,长int,未签名的长int,长long int或未签名的长long int。
如果该列表中的任何类型都不能代表枚举的所有值,则可以将未登记类型的序数转换为具有最低整数转换等级([CORV.RANK])的扩展整数类型的provalue长期的列表可以表示枚举的所有值。
如果有两种扩展类型,则选择签名。

我可以问我的猜测是否正确吗?

在这种情况下, int 是一个正确的猜测不普遍适用。

May I ask why complier matches ff(char) instead of ff(int)?

Because an enum with fixed underlying type can implicitly convert to its underlying type. The underlying type is char and thus the conversion to char is the most preferred candidate overload.

So my current guess goes like this: If we don't explicitly specify the underlying type, then the object/enumerator passed to the integral parameter will first be casted into an int.

A cast is an explicit conversion. The conversion in this example is implicit.

The exact preferred conversion depends on the values of the enum. The language rule is a bit complex, so I'll copy it verbatim from the standard:

[conv.prom]

A prvalue of an unscoped enumeration type whose underlying type is not fixed can be converted to a prvalue of the first of the following types that can represent all the values of the enumeration ([dcl.enum]): int, unsigned int, long int, unsigned long int, long long int, or unsigned long long int.
If none of the types in that list can represent all the values of the enumeration, a prvalue of an unscoped enumeration type can be converted to a prvalue of the extended integer type with lowest integer conversion rank ([conv.rank]) greater than the rank of long long in which all the values of the enumeration can be represented.
If there are two such extended types, the signed one is chosen.

May I ask if my guess is correct?

In this case, int is a correct guess because it is the first type in the list of the quoted standard rule, and it can represent all values of the enum which are 0, 1 2. But the guess does not apply universally.

吝吻 2025-01-28 05:06:52

从C ++ 17标准(7.6积分促销)

3一个未引人注目的枚举类型的贵族,其基础类型为
未固定(10.2)可以转换为第一个
以下可以表示枚举的所有值的类型
(即,如10.2中所述,BMIN到BMAX的值):
int,unsiged int,long int,未签名的长int,长长的int或
未签名的长长
。如果该列表中的任何类型都不能
表示枚举的所有值,
枚举类型可以转换为扩展整数的序幕
类型最低整数转换等级(7.15)大于等级
枚举的所有价值都可以是长期长期
代表。如果有两种此类扩展类型,则签名是
选择。

4 一个未指示的枚举类型的贵族,其基础类型为
固定(10.2)可以转换为其基础类型的序言

此外,如果可以将整体促销应用于其基础类型,则
潜在的枚举类型的贵族,其基础类型是
固定也可以转换为晋升的基础
类型

和(16.3.3.2排名隐式转换序列)

(4.2) - 一种促进枚举的转换
类型固定在其基础类型上比促进的类型要好
如果两者不同。

因此,由于由于积分促销的积分促销,因此转换为固定的基础类型CHAR优于基础类型char向INT的转换,因此选择具有参数char的函数作为最可行的函数。

我还注意到,如果我不明确指定基础类型
对于ABC,然后将ff(int)调用。

因为根据“ 7.6积分促销”部分的报价#3,枚举类型至少将枚举类型推广到类型 int

但是,如果您要声明枚举,例如以下演示程序中所示的以下方式:

#include <iostream>
#include <limits>

enum ABC
{
    a = std::numeric_limits<unsigned int>::max(), b, c
};

void ff( char c )
{
    std::cout << "char\n";
}

void ff( int i )
{
    std::cout << "int\n";
}

int main()
{
    ff( a );
}

那么函数调用将是模棱两可的。

From the C++ 17 Standard (7.6 Integral promotions)

3 A prvalue of an unscoped enumeration type whose underlying type is
not fixed (10.2) can be converted to a prvalue of the first of the
following types that can represent all the values of the enumeration
(i.e., the values in the range bmin to bmax as described in 10.2):
int, unsigned int, long int, unsigned long int, long long int, or
unsigned long long int
. If none of the types in that list can
represent all the values of the enumeration, a prvalue of an unscoped
enumeration type can be converted to a prvalue of the extended integer
type with lowest integer conversion rank (7.15) greater than the rank
of long long in which all the values of the enumeration can be
represented. If there are two such extended types, the signed one is
chosen.

4 A prvalue of an unscoped enumeration type whose underlying type is
fixed (10.2) can be converted to a prvalue of its underlying type
.
Moreover, if integral promotion can be applied to its underlying type,
a prvalue of an unscoped enumeration type whose underlying type is
fixed can also be converted to a prvalue of the promoted underlying
type

and (16.3.3.2 Ranking implicit conversion sequences)

(4.2) — A conversion that promotes an enumeration whose underlying
type is fixed to its underlying type is better than one that promotes
to the promoted underlying type, if the two are different.

So as the conversion to the fixed underlying type char is better than the conversion of the underlying type char to int due to the integral promotions then the function with the parameter char is selected as the most viable function.

I also noticed that if I don't explicitly specify the underlying type
for ABC, then ff(int) will be called.

Because according the quote #3 from the section "7.6 Integral promotions" the enumeration type is promoted at least to the type int.

However if you will declare the enumeration for example the following way as shown in the demonstration program below:

#include <iostream>
#include <limits>

enum ABC
{
    a = std::numeric_limits<unsigned int>::max(), b, c
};

void ff( char c )
{
    std::cout << "char\n";
}

void ff( int i )
{
    std::cout << "int\n";
}

int main()
{
    ff( a );
}

then the function call will be ambiguous.

栖竹 2025-01-28 05:06:52

指定枚举的基础类型将 de exto 将其立即与此基础类型兼容:这就是为什么它是您示例中调用的 char 版本的原因。

与C/C ++, int 一样,隐式的基础类型与往常一样。当您不用枚举指定类型时,就会发生这种情况 - 因此 int 版本首先称为。

但是在我的编译器上(MSVC2017尝试时),即使是第一种情况也不起作用:我得到了“呼叫'ff'是模棱两可的 > char 版本...可能是因为 abc_char enum ,而不是“真正的“ char”,而不是真正的“ int”,而是与通过隐式演员。

ff 的其他调用不会产生任何错误 - int 版本,没有任何警告。

请参阅下面的代码:

#include <iostream>

enum ABC_char : char { a1, b1, c1 } ;
enum ABC_short : short int { a2, b2, c2 } ;
enum ABC_int { a3, b3, c3 } ;

void ff(char)
{
    std::cout << "char" << std::endl ;
}

void ff(int)
{
    std::cout << "int" << std::endl ;
}

int main()
{
    ff(a1) ;    // Call to 'ff' is ambiguous
    ff(a2) ;    // short int -> int
    ff(a3) ;    // int -> int
}

ff(a1)指令甚至不会编译。编译器看到两个候选功能,并且不假定两者中的任何一个。

但是此代码适用于所有呼叫/枚举:

#include <iostream>

enum ABC_char : char { a1, b1, c1 } ;
enum ABC_short : short int { a2, b2, c2 } ;
enum ABC_int { a3, b3, c3 } ;

template < typename T > void ff ( T c )
{
    std::cout << typeid(c).name() << " / " << typeid(std::underlying_type_t<T>).name() << std::endl ;
}

int main()
{
    ff(a1) ;    // enum ABC_char / char
    ff(a2) ;    // enum ABC_short / short
    ff(a3) ;    // enum ABC_int / int
}

您可以在模板中使用 std :: is_same 和一些 constexpr 条件,以确保您称呼为“正确的”行为您的功能:

template < typename T > void ff2 ( T )
{
    if constexpr (std::is_same<std::underlying_type_t<T>, char>()) {
        std::cout << "Using char version" << std::endl ;
    } else
    if constexpr (std::is_same<std::underlying_type_t<T>, int>()) {
        std::cout << "Using int version" << std::endl ;
    } else {
        std::cout << "I have luck!" << std::endl ;
    }
}

int main()
{
    ff2(a1) ;    // Using char version
    ff2(a2) ;    // I have luck!
    ff2(a3) ;    // Using int version
}

Specifying the underlying type for an enum will de facto set it as immediately compatible with this underlying type: that's why it's the char version that is called in your example.

The implicit underlying type is, as usual in C/C++, int. It's what happens when you don't specify a type with your enum - so the int version is called first.

But on my compiler (MSVC2017 when I tried), even the first case don't work: I got a "Call to 'ff' is ambiguous" for the char version... Probably because ABC_char is an enum, not "really" a char, and not "really" an int, but is compatible with both through implicit cast.

Other calls to ff don't produce any error - int version is called without a single warning.

See below code:

#include <iostream>

enum ABC_char : char { a1, b1, c1 } ;
enum ABC_short : short int { a2, b2, c2 } ;
enum ABC_int { a3, b3, c3 } ;

void ff(char)
{
    std::cout << "char" << std::endl ;
}

void ff(int)
{
    std::cout << "int" << std::endl ;
}

int main()
{
    ff(a1) ;    // Call to 'ff' is ambiguous
    ff(a2) ;    // short int -> int
    ff(a3) ;    // int -> int
}

The ff(a1) instruction won't even compile. Compiler sees two candidate functions and don't assume any of the two.

But this code works for all calls/enums:

#include <iostream>

enum ABC_char : char { a1, b1, c1 } ;
enum ABC_short : short int { a2, b2, c2 } ;
enum ABC_int { a3, b3, c3 } ;

template < typename T > void ff ( T c )
{
    std::cout << typeid(c).name() << " / " << typeid(std::underlying_type_t<T>).name() << std::endl ;
}

int main()
{
    ff(a1) ;    // enum ABC_char / char
    ff(a2) ;    // enum ABC_short / short
    ff(a3) ;    // enum ABC_int / int
}

You could, in template, use std::is_same and some constexpr conditions to ensure that you call the "correct" behavior for your function:

template < typename T > void ff2 ( T )
{
    if constexpr (std::is_same<std::underlying_type_t<T>, char>()) {
        std::cout << "Using char version" << std::endl ;
    } else
    if constexpr (std::is_same<std::underlying_type_t<T>, int>()) {
        std::cout << "Using int version" << std::endl ;
    } else {
        std::cout << "I have luck!" << std::endl ;
    }
}

int main()
{
    ff2(a1) ;    // Using char version
    ff2(a2) ;    // I have luck!
    ff2(a3) ;    // Using int version
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文