c++ - 最佳可行的转换函数

标签 c++ language-lawyer implicit-conversion overload-resolution reference-binding

在下面的程序中,应该选择哪个(如果有)转换函数,为什么?

int r;
struct B {};
struct D : B {};
struct S {
  D d;
  operator D&(){r=1; return d;} // #1
  operator B&(){r=2; return d;} // #2
};
int main() {
  S s;
  B& b = s;
  return r;
}

gcc 和 clang select 都选择转换函数#2。但为什么呢?

标准says :

(1) Under the conditions specified in [dcl.init.ref], a reference can be bound directly to the result of applying a conversion function to an initializer expression. Overload resolution is used to select the conversion function to be invoked. Assuming that “reference to cv1 T” is the type of the reference being initialized, and “cv S” is the type of the initializer expression, with S a class type, the candidate functions are selected as follows:

(1.1) - The conversion functions of S and its base classes are considered. Those non-explicit conversion functions that are not hidden within S and yield type “lvalue reference to cv2 T2” (when initializing an lvalue reference or an rvalue reference to function) or “cv2 T2” or “rvalue reference to cv2 T2” (when initializing an rvalue reference or an lvalue reference to function), where “cv1 T” is reference-compatible with “cv2 T2”, are candidate functions. For direct-initialization, those explicit conversion functions that are not hidden within S and yield type “lvalue reference to cv2 T2” (when initializing an lvalue reference or an rvalue reference to function) or “rvalue reference to cv2 T2” (when initializing an rvalue reference or an lvalue reference to function), where T2 is the same type as T or can be converted to type T with a qualification conversion, are also candidate functions.

(2) The argument list has one argument, which is the initializer expression. [ Note: This argument will be compared against the implicit object parameter of the conversion functions. — end note  ]

这里我们有两个候选函数#1 和#2。两者都是可行的——如果删除其中之一,程序仍然可以编译。 两个转换函数仅采用隐式参数,并具有相同的 cv 和 ref 限定。因此,没有一个应该是最好的可行的,并且程序不应该编译。为什么会编译?

最佳答案

嗯,如您所知,重载决议发生在三个阶段:(1)枚举候选函数; (2) 确定哪些候选功能可行; (3)选择最佳可行函数。

根据[over.match.best]/1:

... a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F1), and then

  • for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,
  • the context is an initialization by user-defined conversion (see 11.6, 16.3.1.5, and 16.3.1.6) and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type of F2 to the destination type [ example ... ] or, if not that,
  • [ ... further tie-breaker rules ... ]

s 到 #1 或 #2 的隐式对象参数所需的隐式转换是身份转换,因此 ICS1(#1) 和 ICS2(#1) 是无法区分的,而第二个要点与此相关。在#1的情况下,需要进行派生到基的转换,以从转换函数的返回类型(即D&)转换为所需的类型(即B&) >。在#2的情况下,标准转换序列是恒等转换(B&B&),这是更好的。因此,在这种情况下,选择函数#2 比#1 更好。

关于c++ - 最佳可行的转换函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56546047/

相关文章:

c++ - 在 read() 上阻塞时线程 'disappears' 我该如何调试它?

c++ - 为什么 fclose 会挂起/死锁? ( Windows )

c++ - 没有明显目标的 std::cout 留在发布的代码中是一件坏事吗?

c++ - 复制构造函数是始终隐式定义,还是仅在使用时定义?

c - C语言的求值顺序

c - 使用指针指向c中的某一行

c++ - 如何正确格式化 C++ 注释?

c++ - 在 C++ 中检测命名空间

scala - "parameterized overloaded implicit methods are not visible as view bounds"编译器警告是什么意思?

c++ - 为什么隐式转换对于非原始类型不模棱两可?