为什么会发生invalid covariant return type
错误?
我正在尝试实现模板基迭代器和派生迭代器。
代码:
template <typename T>
class BaseClassA{
public:
virtual bool operator!=(const BaseClassA<T> & A) const {}
virtual BaseClassA<T> operator++(T){}
} ;
template <typename T>
class DerivedClassA: public BaseClassA<T>{
private:
T* p;
public:
DerivedClassA<T> operator++(T){
DerivedClassA<T> tmp(*this);
++p;
return tmp;
}
bool operator!=(const DerivedClassA<T> & A) const {
return (A.p != p);
}
} ;
template <typename T>
class BaseClassB{
private:
BaseClassA<T> beginIter;
BaseClassA<T> endIter;
public:
virtual BaseClassA<T> begin(void){}
virtual BaseClassA<T> end(void){}
} ;
template <typename T>
class DerivedClassB{
private:
DerivedClassA<T> beginIter;
DerivedClassA<T> endIter;
public:
DerivedClassA<T> begin(void){ return beginIter; }
DerivedClassA<T> end(void){ return endIter; }
} ;
int main(void){
DerivedClassB<int> B;
B.begin() != B.end();
++B.begin();
}
编译器错误(g ++)
test.cpp: In instantiation of 'class DerivedClassA<int>':
test.cpp:35:26: required from 'class DerivedClassB<int>'
test.cpp:43:24: required from here
test.cpp:12:27: error: invalid covariant return type for 'DerivedClassA<T> DerivedClassA<T>::operator++(T) [with T = int]'
DerivedClassA<T> operator++(T){
^
test.cpp:5:31: error: overriding 'BaseClassA<T> BaseClassA<T>::operator++(T) [with T = int]'
virtual BaseClassA<T> operator++(T){}
^
test.cpp: In function 'int main()':
test.cpp:45:5: error: no match for 'operator++' (operand type is 'DerivedClassA<int>')
++B.begin();
^
test.cpp:45:5: note: candidate is:
test.cpp:12:27: note: DerivedClassA<T> DerivedClassA<T>::operator++(T) [with T = int]
DerivedClassA<T> operator++(T){
^
test.cpp:12:27: note: candidate expects 1 argument, 0 provided
答案 0 :(得分:1)
C ++只直接支持原始指针和原始引用的协变结果类型。
一个原因是因为对于类类型,协变结果可能需要比调用者更多的空间,只知道基类声明,为此结果留出了空间。
示例中的模板与此问题无关。
在其他新闻中:
您不需要虚拟operator==
,因为您不希望运行时检查相等比较的有效性,实际上您不需要。
operator++()
和operator++(int)
是唯一的两个有效签名,因此您无法对参数类型进行有意义的模板化。
答案 1 :(得分:1)
C ++内置协方差适用于C ++对象模型中的引用和指针。
现在这是C ++。因此,如果您不喜欢C ++提供的内容,您可以编写自己的对象模型。
在你的情况下你有迭代器。这些迭代器希望成为值类型(因为这是C ++在其库中想要的),并且您希望它们是多态的。
使用C ++对象模型不支持多态值类型。
使用code like this或adobe poly或boost type erasure或boost any_range,您可以创建支持值类型多态的鸭型多态系统。
现在,您的BaseClassB<T>::begin
和end
会返回any_iterator<T>
。符合概念的内容(包括DerivedClassA<T>
)可以在其中存储和操作。 BaseClassA<T>
变得过时,因为删除迭代器的类型不需要多态的虚基类。
DerivedClassB<T>
也会返回any_iterator<T>
。如果你想要对DerivedClassB<T>
的真实迭代器进行裸访问有一个名为get_naked_range()
的函数,它返回DerivedClassB<T>
的裸迭代器,它可以在你绝对确定类型是的上下文中使用。 DerivedClassB<T>
。如果您这样做,也请将begin
和end
标记为final
。
请注意,此类型擦除具有运行时成本,并且迭代它将比“原始裸”迭代慢。这只有在高性能环境中以相当低的水平执行此操作时才重要,不要让它吓跑你。