【问题标题】:friend operator in nested class of templated class模板类的嵌套类中的友元运算符
【发布时间】:2023-03-11 03:00:01
【问题描述】:

我想为我的向量类添加一个迭代器类类型,我将一些比较运算符声明为迭代器类的友元函数。但它没有正确编译,我做了前向声明。

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

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

请帮帮我,非常感谢。

【问题讨论】:

  • 请每个 stackoverflow.com 问题一个问题。
  • @Chipster - 抱歉,我有时会通过语言律师考试,可能不应该使用这个词。我可以像my_func&lt;int&gt;(42) 这样调用函数模板的实例。但是如果编译器可以从函数参数中推断出模板参数,我可以说my_func&lt;&gt;(42)。这就是那行正在做的事情,只是带有一个函数签名。
  • @parktomatomi 哦,知道了。我现在明白了。
  • @zxy1122 您提供的声明在 VS 2019 上对我来说在 VS 2019 上编译得很好。您能澄清一下您编写的触发错误的代码吗?

标签: c++ templates


【解决方案1】:

在您的前向声明中

template<class object>
bool operator<(typename vector<object>::const_iterator&, 
               typename vector<object>::const_iterator&);

const_iterator 在非推导上下文中,即编译器将无法在以下调用中为 object 推导 int:

vector<int>::const_iterator c1;
vector<int>::const_iterator c2;

c1 < c2;

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

  1. 最简单的一个:省略你的前向声明并在const_iterator 的主体内为operator&lt; 提供一个定义:

    friend bool operator<(const_iterator& lhs, const_iterator& rhs) {
        ... return ... ;        
    }
    
  2. 如果您无法在const_iterator 中定义operator&lt;,请使用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&lt; 是第一个解决方案中的函数模板吗?为什么我们在operator&lt; 之后不需要&lt;&gt;?

  1. It is not a template。在这个定义中你不需要&lt;&gt;。

  2. 您先转发声明一个模板。如果没有&lt;&gt;,朋友声明会引入非模板函数。一个非模板函数,即使它与模板一同名(非模板和模板函数可以重载!),也应该在某个地方定义。如果没有这样的定义,你会得到一个链接错误。要覆盖默认行为并引用之前前向声明的函数模板,请添加 &lt;&gt;。

【讨论】:

  • 谢谢,运算符 。我有点困惑。
  • @zxy1122,在this question之后更正了答案。
猜你喜欢
  • 1970-01-01
  • 2011-05-08
  • 1970-01-01
  • 2013-09-20
  • 2021-05-18
  • 2011-06-07
  • 2010-11-20
相关资源
最近更新 更多