使用转换函数时出现模棱两可的重载错误

Ambiguous overload error when using conversion function

我试图通过列出的书籍 here 来理解 C++ 中的重载解析。下面给出了我写的一个这样的例子,以清除我无​​法理解其输出的概念。


#include <iostream>
struct Name 
{
  operator int() 
  {
      std::cout<<"Name's int version called"<<std::endl;
      return 4;
  }
  operator float() 
  {
      std::cout<<"Name's float version called"<<std::endl;
      return 1.1f;
  }
  
};
int main()
{
    
    double a = Name(); //this works and calls Name's float version. But WHY ISN'T THIS AMBIGIOUS?
    long double b = Name();  //this does not work. WHY IS THIS AMBIGIOUS?
    bool c = Name();  //this does not work. WHY IS THIS AMBIGIOUS? 
     
    return 0;
}

如您所见,here 该程序在创建 double a 时运行。但是当我尝试创建对象 bc 时,它给出了错误。

我的问题是:

  1. 为什么我们没有得到对象 a 的歧义错误。即在className中的两个转换运算符中,为什么选择float版本而不是int版本。

  2. Why/how 我们是否得到对象 b 的歧义错误,它是一个 long double。这就像 a 一样,我怀疑应该调用 float 版本,但我们得到了错误。这与上面的 double a 案例有何不同。

  3. Why/how 我们是否得到对象 c 的歧义错误,即 bool。在这种情况下,我怀疑可能已经选择了 int 版本,但我们却得到了一个错误。这与使用 float 版本转换函数的 double a 版本有何不同。

我只是想了解 why/how 第一个版本有效,但其他两个无效。

本质上,跳过一些在这种情况下不相关的东西,完成重载决策以选择 user-defined 转换函数来初始化变量和(因为转换运算符之间没有其他差异)最好的根据将 return 值转换为变量类型所需的标准转换序列的等级来选择可行的。


转换 int -> double 是一个 floating-integral 转换,其等级为 转换.

转换 float -> doublefloating-point 促销,排名为 促销

排名 promotion 优于排名 conversion,因此重载解析将选择 operator float 作为最佳可行过载。


转换int -> long double也是floating-integral转换

转换 float -> long double 不是 floating-point 促销(仅适用于转换 float -> double).相反,它是 floating-point 转换,其排名为 转换

两个序列现在具有相同的标准转换序列等级,并且 tie-breakers 的 none(我不会通过)适用,因此重载解析是不明确的。


转换 int -> bool 是一个 布尔值转换 ,其等级为 conversion.

转换float -> bool也是布尔转换

所以出现和上面一样的情况


有关转换类别和排名的完整列表,请参阅 https://en.cppreference.com/w/cpp/language/overload_resolution#Ranking_of_implicit_conversion_sequences and https://en.cppreference.com/w/cpp/language/implicit_conversion


虽然看起来 floating-point 类型之间的转换应该被认为比从整数到 floating-point 类型的转换“更好”,但通常情况并非如此。

在此初始化

double a = Name();

有使用浮动积分促销.

C++ 17 标准(7.7 Floating-point 提升)

1 A prvalue of type float can be converted to a prvalue of type double. The value is unchanged. 2 This conversion is called floating-point promotion

对于 returns 类型 int 对象的转换函数,使用了比 floating-point 提升级别低的转换。

也就是说,具有提升等级的转换函数比具有转换等级的函数更可行。

在这些声明中

long double b = Name();
bool c = Name();

使用了从int和float类型到long double和bool类型的转换。所以两种转换都不是更好。这两个函数都有转换等级。