本文介绍了(GCC 错误?)隐式转换为派生类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 C++ 中遇到了隐式转换的问题.下面是一个最小的例子:

I've encountered a problem with implicit conversion in C++. The following is a minimal example:

struct A {
  virtual void f()=0; // abstract
};

struct Ad : A {
  virtual void f() {} // not abstract
};

struct B {
  operator Ad () const { return Ad(); }
};

void test(A const &lhs) {}

int main()
{
  B b;
  test(b);
}

我希望编译器做的是:将 b 转换为 Ad 类型的变量(使用 B 中定义的转换)并将结果传递给 test.但是,上面的代码不能在 GCC 中编译(启用 C++11),结果是无法分配抽象类型 'A' 的对象.

What I would like the compiler to do is: convert b to a variable of type Ad (using the conversion defined in B) and pass the result to test. However, the above code does not compile in GCC (with C++11 enabled), the result being Cannot allocate an object of abstract type 'A'.

注意事项:

  1. Clang 编译这个.
  2. 如果您通过将 f()=0; 更改为 f() {} 使 A 成为非抽象的,则代码工作正常.
  3. 编译器确实找到了转换运算符(如 2 所示),但它没有做我希望它做的事情.
  1. Clang compiles this.
  2. If you make A non-abstract by changing f()=0; to f() {}, the code works just fine.
  3. The compiler does find the conversion operator (as indicated by 2), but it doesn't do what I'd like it to do.

推荐答案

中定义.
现在考虑链接的 13.3.1.6:

And reference-compability is defined in [dcl.init.ref]/4.
Now consider the linked 13.3.1.6:

在8.5.3规定的条件下,可以绑定一个引用直接到作为应用结果的泛左值或类纯右值到初始化表达式的转换函数.超载分辨率用于选择要调用的转换函数.假设cv1 T"是引用的底层类型正在初始化,cv S"是初始化器的类型表达式,以 S 为类类型,候选函数为选择如下:

  • 考虑了S及其基类的转换函数.那些非显式转换函数隐藏在 S 和 yield 类型lvalue reference to cv2 T2"(初始化左值引用时或右值引用时函数)或cv2 T2" [..],其中cv1 T"与cv2 T2"引用兼容(8.5.3),是候选函数.对于直接初始化,[..].
  • 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" [..], where "cv1 T" is reference-compatible (8.5.3) with "cv2 T2", are candidate functions. For direct-initialization, [..].

如您所见,您的转换函数不是本段之后的候选函数.因此 [dcl.init]/5 中的下一个项目符号适用:

As you can see, your conversion function isn't a candidate after this paragraph. Thus the next bullet in [dcl.init]/5 is applicable:

否则:

  • 如果 T1 是类类型,则使用cv1 类型的对象的复制初始化规则考虑用户定义的转换T1" 由用户自定义转换 (8.5, 13.3.1.4);该程序是如果相应的非引用复制初始化,则格式错误将是畸形的.调用转换的结果函数,如非引用复制初始化所述,是然后用于直接初始化引用.该程序是如果直接初始化不会导致直接绑定或者是否涉及用户定义的转换.
  • If T1 is a class type, user-defined conversions are considered using the rules for copy-initialization of an object of type "cv1 T1" by user-defined conversion (8.5, 13.3.1.4); the program is ill-formed if the corresponding non-reference copy-initialization would be ill-formed. The result of the call to the conversion function, as described for the non-reference copy-initialization, is then used to direct-initialize the reference. The program is ill-formed if the direct-initialization does not result in a direct binding or if it involves a user-defined conversion.

注意短语程序是如果相应的非引用复制初始化,则格式错误将是不正确的"可能意味着

B b;
A a = b;

格式错误,程序格式错误.我认为这是措辞的缺陷或含糊不清,而不是 GCC 不接受代码的原因.当然,措辞仅针对初始化本身,而不是首先可以创建类型为 T1(又名 A)的大多数派生对象.
最后13.3.1.4接受我们的转换函数:

is ill-formed, the program is ill-formed. I believe this to be a defect or vagueness in the wording though, and not the reason that GCC does not accept the code. Assuredly the wording solely aims at the initialization itself, not the fact that a most-derived object of type T1 (aka A) can be created in the first place.
Finally 13.3.1.4 accepts our conversion function:

假设cv1 T"是被初始化对象的类型,以T为类类型,候选函数被选为如下:

  • T 的转换构造函数 (12.3.1) 是候选函数.
  • 当初始化表达式的类型为类类型cv S"时,S的非显式转换函数及其根据类被考虑.[..].那些没有隐藏在S中的并产生一个类型,其 cv-unqualified versionT 是其派生类是候选函数.
  • The converting constructors (12.3.1) of T are candidate functions.
  • When the type of the initializer expression is a class type "cv S", the non-explicit conversion functions of S and its base classes are considered. [..]. Those that are not hidden within S and yield a type whose cv-unqualified version is the same type as T or is a derived class thereof are candidate functions.

现在最后一个问题是是否在

Now the last question is whether in

A const& ref(Ad());

ref 是直接绑定的.确实如此.
因此原始参数引用直接绑定,不必创建 A 类型的大多数派生对象.
GCC 可能认为必须初始化类型为 A 的临时文件,并将引用绑定到该临时文件.或者迂腐地遵循上述有缺陷的措辞,这种可能性很小.

ref is bound directly. And it is.
Thus the original parameter reference binds directly, and no most-derived object of type A must be created.
What GCC presumably thinks is that a temporary of type A must be initialized and the reference be bound to that temporary. Or it pedantically follows the above defected wording, which is very unlikely.

1)

给定类型cv1 T1"和cv2 T2"、cv1"em> T1" 与引用相关cv2 T2" 如果 T1T2 的类型相同,T1T2 的基类.如果 T1cv1 T1" 与cv2 T2" 引用兼容是与 T2cv1 相关的引用与 或比 cv2 更高的 cv 资格.

这篇关于(GCC 错误?)隐式转换为派生类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-18 13:04