c++ - 协变返回类型无法识别

标签 c++

出于某种原因,最新版本的 GCC 和 clang 在这种特定情况下都不能识别返回类型协方差。错误信息具有误导性:

error: return type of virtual function 'foo' is not covariant with the return
     type of the function it overrides ('derived *' is not derived from 'base *')

代码如下:

class base
{
private:
  virtual base * foo() = 0;
};

template< class T >
class foo_default_impl : public virtual base
{
private:
  T * foo() override { return nullptr; }
};

class derived : public virtual base, private foo_default_impl< derived >
{
};

int main() {
  derived d{}; // error: return type of virtual function 'foo' is not covariant with the return type of the function it overrides ('derived *' is not derived from 'base *')
  return 0;
}

最佳答案

事情就是这样。虽然在我们看来,编译器似乎知道它需要知道的关于所讨论类型的一切,但标准却另有规定。

[temp.arg.type/2]

... [ Note: A template type argument may be an incomplete type. — end note ]

[basic.types/5]

A class that has been declared but not defined, an enumeration type in certain contexts ([dcl.enum]), or an array of unknown bound or of incomplete element type, is an incompletely-defined object type.46 Incompletely-defined object types and cv void are incomplete types ([basic.fundamental]). Objects shall not be defined to have an incomplete type.

[class/2]

A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name. For purposes of access checking, the injected-class-name is treated as if it were a public member name. A class-specifier is commonly referred to as a class definition. A class is considered defined after the closing brace of its class-specifier has been seen even though its member functions are in general not yet defined. The optional attribute-specifier-seq appertains to the class; the attributes in the attribute-specifier-seq are thereafter considered attributes of the class whenever it is named.

粗体文本描绘了所讨论的编译器将类型参数 T 视为不完整对象类型的简单图景。就好像你只转发声明它,像这样:

class derived;

他们不能推断出这个前向声明是从 base 派生的类。 .所以他们不能接受它作为 foo_default_impl 上下文中的协变返回类型。 . @marcinj in the comments 指出了类似的情况:

[class.virtual/8]

If the class type in the covariant return type of D​::​f differs from that of B​::​f, the class type in the return type of D​::​f shall be complete at the point of declaration of D​::​f or shall be the class type D.

自从 T既不完整,也不是foo_default_impl<T>本身,它不能是协变返回类型。

关于c++ - 协变返回类型无法识别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44548242/

相关文章:

c++ - 是否有可能知道是否包含标题

C++ 重载或监视解引用运算符(在指针上)

c++ - Makefile 在同一目录中找不到文件

c++ - 如何在运行时检测符号是否被剥离?

c++ - 带参数和不带参数的函数之间的执行时间/C++

c++ - 编译时计算迭代的可能性

c++ - 从源代码构建的 Clang 编译 C 但不编译 C++ 代码

c++ - sscanf 多个输入

c++ - 如何获取 crtdbg.h 文件?

c++ - QT中如何修改键盘输入?