【问题标题】:Does C++ guarantee this enum vs int constructor overload resolution?C++ 是否保证此枚举与 int 构造函数重载解析?
【发布时间】:2021-12-18 13:26:10
【问题描述】:

考虑这个示例程序:

#include <iostream>

typedef enum { A, B, C } MyEnum;

struct S
{
    S(int) { std::cout << "int" << std::endl; }
    S(MyEnum) { std::cout << "MyEnum" << std::endl; }
};

S f()
{
    return A;
}

int main()
{
    S const s = f();
}

使用 clang 和 gcc 编译,这会生成一个在运行时打印“MyEnum”的可执行文件。 C++ 标准是否保证这种行为?

【问题讨论】:

  • 让事情变得更有趣:godbolt.org/z/exf6bY7de
  • 这并没有解决问题,但在 C++ 中,您不必跳 typedef enum ... MyEnum; 舞蹈。 enum MyEnum ...; 工作得很好。 typedef 是 C 主义; C++ 处理类型名称的方式不同。

标签: c++ implicit-conversion overload-resolution


【解决方案1】:

是的,S::S(MyEnum)overload resolution 中获胜,因为它是完全匹配的。而S::S(int) 需要一个从枚举到intimplicit conversion (integral promotion)。

每种类型的标准转换序列都被分配三个等级之一:

  1. 完全匹配:无需转换、左值到右值转换、限定 > 转换、函数指针转换、(C++17 起)用户定义的类类型到同一类的转换
  2. 推广:积分推广、浮点推广
  3. 转换:整数转换、浮点转换、浮点整数转换、指针转换、指针到成员的转换、布尔转换、派生类到其基类的用户定义转换

标准转换序列 S1 优于标准转换序列 S2 if

a) S1 是 S2 的子序列,不包括左值变换。身份转换序列被视为任何其他转换的子序列

b) 或者,如果不是这样,S1 的排名优于 S2 的排名

如果 F1 的所有参数的隐式转换不比 F2 的所有参数的隐式转换差,则确定 F1 是比 F2 更好的函数,并且

  1. 至少有一个 F1 参数的隐式转换优于 F2 该参数的相应隐式转换

这些成对比较适用于所有可行的功能。如果恰好一个可行的函数优于所有其他函数,则重载决议成功并调用此函数。否则编译失败。

【讨论】:

    【解决方案2】:

    是的,当然。 return 语句允许隐式构造,S(MyEnum) 是完全匹配的。

    同样适用于return {A};

    但如果你要明确S(MyEnum),那么:

    • return A; 将调用 S(int) 作为后备,因为 MyEnum 可以隐式转换为整数。但由于额外的转换,这比S(MyEnum) 更糟糕的重载候选者,仅根据需要选择。
    • return {A}; 代表复制列表初始化。它将失败,因为它禁止显式构造函数和隐式转换。
    • return S{A}; 代表直接列表初始化,它会调用S(MyEnum),虽然它限制了一些隐式转换,但它不影响这个例子,如果S(MyEnum) 被删除,S(int) 将被调用。
    • 在指定返回类型S 的情况下,return S(A); 本质上与return A; 相同。

    【讨论】:

    • 有趣的是,如果我删除 S(MyEnum) 构造函数,return S{A}; 仍然可以工作并调用 S(int) 构造函数。所以看起来 {} 允许隐式枚举 -> int 转换。
    • @khuttun 抱歉,我搞砸了。 return S{A}direct list initialization... C++ 初始化规则的乐趣。
    猜你喜欢
    • 2011-08-20
    • 2020-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-18
    相关资源
    最近更新 更多