我想为我的向量类添加一个迭代器类类型,并声明一些比较运算符作为迭代器类的友好函数。但是它编译不正确,所以我做了前向声明。
template<class object>class vector;
template<class object>
bool operator<(typename vector<object>::const_iterator& lhs, typename vector<object>::const_iterator& rhs);
template<class object>class vector {
protected:
//some member
public:
class const_iterator {
friend bool operator< <>(const_iterator& lhs, const_iterator& rhs);
friend bool operator> <>(const_iterator& lhs, const_iterator& rhs);
//...
};
};
编译器说没有找到匹配的重载函数,我使用的是vs2019。我猜正向声明有问题。
另一个问题是,我注意到有人在类中声明好友函数时使用了这种形式。
class myclass{
friend void foo<T>(T t);
//...
}
但是当将运算符声明为朋友时,会有所不同
friend bool operator< <>(const myclass& lhs, const myclass& rhs);
我想知道两者之间有什么区别。
请多多帮助。
答案 0 :(得分:1)
在您的前向声明中
template<class object>
bool operator<(typename vector<object>::const_iterator&,
typename vector<object>::const_iterator&);
const_iterator
在非推论上下文中,即,在以下调用中,编译器将无法为int
推论object
:
vector<int>::const_iterator c1;
vector<int>::const_iterator c2;
c1 < c2;
我可以提出两种解决方案。
最简单的方法:省略您的前向声明,并在operator<
的正文中为const_iterator
提供一个定义:
friend bool operator<(const_iterator& lhs, const_iterator& rhs) {
... return ... ;
}
如果您无法在operator<
中定义const_iterator
,请使用CRTP将非推论上下文转换为推论上下文:
template<class derived>
struct const_iterator_crtp {};
template<class derived>
bool operator<(const_iterator_crtp<derived>&,
const_iterator_crtp<derived>&);
template<class object>
struct vector {
struct const_iterator : const_iterator_crtp<const_iterator> {
using base = const_iterator_crtp<const_iterator>;
friend bool operator< <>(base&, base&);
private:
int priv;
};
};
template<class derived>
bool operator<(const_iterator_crtp<derived>& lhs,
const_iterator_crtp<derived>& rhs)
{
auto& l = static_cast<derived&>(lhs); // these static_cast's are safe
auto& r = static_cast<derived&>(rhs);
return l.priv < r.priv;
}
第一个解决方案中的
operator<
是功能模板吗?为什么在<>
之后不需要operator<
?
It is not a template。您不需要在此定义中使用<>
。
您先声明一个模板。如果没有<>
,则朋友声明会引入非模板函数。一个非模板函数,即使它的名称与模板名称相同(非模板和模板函数可能会重载!),也应在某处定义。如果没有这样的定义,您将获得链接错误。要覆盖默认行为并引用之前已预先声明的功能模板,请添加<>
。