模板类的嵌套类中的Friend运算符

时间:2019-11-13 03:30:37

标签: c++ templates

我想为我的向量类添加一个迭代器类类型,并声明一些比较运算符作为迭代器类的友好函数。但是它编译不正确,所以我做了前向声明。

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);

我想知道两者之间有什么区别。

请多多帮助。

1 个答案:

答案 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;

我可以提出两种解决方案。

  1. 最简单的方法:省略您的前向声明,并在operator<的正文中为const_iterator提供一个定义:

    friend bool operator<(const_iterator& lhs, const_iterator& rhs) {
        ... return ... ;        
    }
    
  2. 如果您无法在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<

  1. It is not a template。您不需要在此定义中使用<>

  2. 您先声明一个模板。如果没有<>,则朋友声明会引入非模板函数。一个非模板函数,即使它的名称与模板名称相同(非模板和模板函数可能会重载!),也应在某处定义。如果没有这样的定义,您将获得链接错误。要覆盖默认行为并引用之前已预先声明的功能模板,请添加<>