CRTP和动态多态性编译错误
CRTP and dynamic polymorphism compile error
class A {
virtual A* foo() = 0;
};
template<class T>
class B : public A {
virtual T* foo() { return nullptr; }
};
class C : public B<C> {
};
这是一个简化的实现可能性混合复合模式和奇怪的重复出现的模板模式。我得到以下错误:
Return type of virtual function 'foo' is not covariant with the return type of the function it overrides ('C *' is not derived from 'A *')
在clang 3.0, gcc 4.7和visual studio 2008上测试。
第一个解决方案:
class C : public A, public B<C> {}
在visual studio下编译时会提示B已经是a的子节点,并且不是在clang下编译时会出现初始错误。
另一个解决方案:
class D : public A {}
class C : public B<D> {}
解决了不完整性问题,但我不知道我将有多少个A实例。直觉告诉我A是虚的,因此应该只有一个。
这个方法也会产生不可读的代码。
对于这种情况,标准是怎么说的?这段代码应该编译吗?如果不是,为什么?
您的虚拟函数A::foo()
返回一个A*
,而函数B<C>::foo()
,这意味着覆盖它,返回一个C*
。
这在理论上确实尊重协方差原则,因为C
确实是A
的专门化(派生),但在实例化时,这是未知的,因为C
是一个不完全类型。
重新考虑设计的一种可能方法是使A
也成为类模板,并让B
将T
的模板参数传播到A
:
template<typename T>
class A {
virtual T* foo() = 0;
};
template<class T>
class B : public A<T> {
virtual T* foo() { return nullptr; }
};
关于你的解决方法:
对于这种情况,标准是怎么说的?这段代码应该编译吗?如果不是,为什么?
不应该编译,因为仅仅使C
也显式地派生自A
这一事实(注意,在C
中最终会有两个不同的A
类型的基本子对象)并不能使C
在实例化B<C>
时成为一个完整的类型。c++ 11标准第9.2/2段:
在类说明符的结尾
}
处,类被认为是完全定义的对象类型(3.9)(或完整类型)。在类成员规范中,类在函数体中被视为完整的;默认参数,以及非静态数据成员的大括号或相等初始化式(包括嵌套类)。否则,在其自己的类成员规范中,它被认为是不完整的。
相关文章:
- std::is_base_of表示ctor编译错误
- Qt5:使用QCommandLineParser类时出现奇怪的编译错误
- 如何修复sfml c++代码编译错误
- 使用 MATLAB 编码器生成C++代码:编译错误"undefined reference to `rgb2gray_tbb_real64'"
- 使用外部SDK工具链文件在VisualStudio上生成项目编译错误
- vscode下的Arduino代码出现意外编译错误
- 第三方 API 中的编译错误 - Visual Studio
- std::cout输出int时出现编译错误
- 奇怪的代码抛出编译错误模板< J,int aSize=10> C2143:语法错误:在"<"之前缺少";"
- 提升图广度优先搜索前置编译错误
- C++ 中的编译错误:未定义对"主"的引用 collect2:错误:ld 返回 1 个退出状态
- 使用带有 ref 参数的成员函数创建线程时出现编译错误
- 我在C++中遇到了这个奇怪的编译错误
- 在C++中使用 Catch 测试框架编译错误"error: expected ';' at end of declaration list"
- 使用 std::enable_if 限制派生类的模板参数时出现编译错误
- 现代OpenGL和GLEW Libraray的编译错误
- C++ 编译错误:意外的类型名称"字符串":预期的表达式
- C ++程序编译错误,找不到/访问文件
- 使用直接大括号初始化时,C++ 编译错误"声明末尾的预期";"
- 为什么传递非静态成员函数会导致编译错误?