【问题标题】:How do I overload % operator for a template class?如何为模板类重载 % 运算符?
【发布时间】:2017-10-29 07:16:38
【问题描述】:

我创建了一个模板类 Number。我重载了

template<typename t>
class Number
{
private:
    t n;
public:
    Number(t a) :n{ a } {};
    Number() :n{ t() } {};
    friend ostream & operator<<<>(ostream & os, const Number<t>& a);
    friend Number<t> operator%(Number<t> a, Number<t> b);
};
template<typename t>
ostream & operator<<<>(ostream & os, Number<t> a)
{
    os << a.n;
    return os;
}
template<typename t> 
Number<t> operator%(Number<t> a, Number<t> b)
{
    return Number<t>(a.n % b.n);
}

正如您在 ,它可以完成这项工作。但是如果我在 % 运算符定义中使用它,我会得到一个语法错误,如果我没有,我会得到 “1 个未解决的外部”错误。所以我的问题可以总结为两个问题—— 1. 为什么在使用友元符号重载运算符时需要使用? 2. 为什么它对 % 运算符不起作用?

【问题讨论】:

  • 该死的好问题。我没有好的答案,你需要一个比我更好地了解模板的人,但我知道如果你将函数定义移到类中,问题就会消失:friend Number&lt;t&gt; operator%(Number&lt;t&gt; a, Number&lt;t&gt; b) { return Number&lt;t&gt;(a.n % b.n); } 废话答案​​,所以这是一个评论,但这就是我所做的继续前进。
  • 因为injected class names,所以不需要在类中显式写&lt;t&gt;

标签: c++ class templates overloading operator-keyword


【解决方案1】:

方法一

在类模板定义之前声明函数。

template <typename t> class Number;

template <typename t>
std::ostream & operator<<(std::ostream & os, const Number<t>& a);

template <typename t>
Number<t> operator%(Number<t> a, Number<t> b);

定义类。确保 friend 声明使用模板参数。

template <typename t>
class Number
{
private:
    t n;
public:
    Number(t a) :n{ a } {};
    Number() :n{ t() } {};

    // This makes sure that operator<< <int> is a friend of Number<int>
    // but not of Number<double>
    friend std::ostream & operator<< <t>(std::ostream & os, const Number& a);
    friend Number operator%<t>(Number a, Number b);
};

在类定义之外实现函数。

template <typename t>
std::ostream & operator<<(std::ostream & os, const Number<t>& a)
{
    os << a.n;
    return os;
}

template <typename t> 
Number<t> operator%(Number<t> a, Number<t> b)
{
    return Number(a.n % b.n);
}

http://ideone.com/dx3fC0 的工作代码。

方法二

在类模板定义中实现friend 函数。

template <typename t>
class Number
{
   private:
      t n;
   public:
      Number(t a) :n{ a } {};
      Number() :n{ t() } {};
      friend std::ostream& operator<<(std::ostream & os, const Number& a)
      {
         os << a.n;
         return os;
      }

      friend Number operator%(Number a, Number b)
      {
         return Number<t>(a.n % b.n);
      }
};

http://ideone.com/5PYQnR 的工作代码。


如果friend 函数不是太复杂,最好使用第二种方法。整体代码结构简单。如果friend 函数很复杂,使用第一种方法并在类定义之外实现它们可能是有意义的。

【讨论】:

  • 谢谢。我想我现在得到了类中真正发生的事情:上述声明的模板特化。并且因为Number的模板在最终投入使用后会被特化,所以我们应该可以多拉一个闪避,在Number的定义之前完全定义模板化的函数。这真的很奇怪,因为现在看起来我们在定义之前使用了 Number 的部分内容。
  • @user4581301,这真的很奇怪,因为现在看起来我们正在使用未定义的 Number 的一部分。 有一个已建立的模式称为 @987654323 @ 正是这样做的。
  • 更好的是,根据一元运算符和/或方法实现二元运算符。那么你就不需要他们成为朋友了。
【解决方案2】:

您应该首先将运算符声明为函数模板,然后再在类中“成为朋友”。有关如何正确执行此操作的更多详细信息,请参阅 thisthis

我怀疑你逃脱operator &lt;&lt; 的原因是你的问题中没有显示using namespace std,它带来了来自&lt;iostream&gt; 的模板化operator &lt;&lt; 声明。

这应该可行:

#include <iostream>

template<typename T>
class Number;

// Declare the operators here.
template<typename T>
std::ostream & operator<<(std::ostream & os, const Number<T>& a);

template<typename T>
Number<T> operator%(Number<T> a, Number<T> b);

template<typename T>
class Number
{
private:
    T n;
public:
    Number(T a) :n{ a } {};
    Number() :n{ T() } {};

    friend std::ostream & operator<< <T>(std::ostream & os, const Number& a);

    friend Number operator% <T>(Number a, Number b);
};

template<typename T>
std::ostream & operator<<(std::ostream & os, const Number<T>& a /* was Number<T> ==> signature mismatch */) 
{
    os << a.n;
    return os;
}

template<typename T> 
Number<T> operator%(Number<T> a, Number<T> b)
{
    return Number<T>(a.n % b.n);
}

int main() {
    Number<int> a(5);
    Number<int> b(6);
    auto c = a % b;
    std::cout << a << std::endl;
    return 0;
}

【讨论】:

    【解决方案3】:

    在类体中定义这些函数并省去麻烦。此外,如果% 的左侧操作数是Number,您不必将其设为朋友。

    #include <iostream>
    
    using std::ostream;
    
    template<typename t>
    class Number
    {
    private:
        t n;
    public:
        Number(t a) :n{ a } {};
        Number() :n{ t() } {};
    
        Number operator%(Number rhs)
        {
            return Number(n % rhs.n);
        }
    
        friend ostream & operator<<(ostream & os, Number a)
        {
           os << a.n;
           return os;
        }
    };
    
    
    int main()
    {
      Number<int> n1(4);
      Number<int> n2(2);
    
      std::cout << n1 << ' ' << n2 << '\n';
    
      Number<int> n3 = n1 % n2;
      std::cout << n3 << '\n';
    }
    

    【讨论】:

      【解决方案4】:

      您可以将朋友运算符本身设为模板化运算符:

      template<typename t>
      class Number
      {
      private:
          t n;
      public:
          Number(t a) :n ( a ){};
          Number() :n( t() ) {};
      
          template<typename TT>
          friend Number<TT> operator%(Number<TT> a,const Number<TT>& b);
      };
      
      template<typename t> 
      Number<t> operator%(Number<t> a,const Number<t> &b)
      {
          return Number<t>(a.n % b.n);
      }
      
      
      int _tmain(int argc, _TCHAR* argv[])
      {
          Number<int> a;
          Number<int> b;
      
          Number<int> c = a %b;
          return 0;
      }
      

      请参阅有关外向声明here 的说明。

      【讨论】:

        猜你喜欢
        • 2021-10-19
        • 1970-01-01
        • 2021-05-18
        • 2011-06-07
        • 2010-11-20
        • 1970-01-01
        相关资源
        最近更新 更多