最佳可行转换函数

Best viable conversion function

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

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 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 限定。所以 none 应该是最好的可行的,程序应该不会编译。为什么会编译?

嗯,如你所知,重载决策分三个阶段进行:(1) 枚举候选函数; (2) 确定哪些候选函数是可行的; (3) select最佳可行函数。

根据[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 的情况下,需要进行 derived-to-base 转换,才能将转换函数的 return 类型,即 D& 转换为所需的类型,即 B&。在#2的情况下,标准的转换顺序是恒等式转换(B& to B&),这样比较好。因此,在这种情况下,功能 #2 被选为比 #1 更好。