2017-05-29 75 views
3

我创建了一个模板类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.为什么它不适用于%操作符?

+1

不错的问题。我没有好的答案,你需要有人谁groks模板远远比我好,但我知道这个问题消失,如果您将函数定义为类:'朋友数操作符%(数量一,数 B) { return number (an%bn); '垃圾回答,所以这是一个评论,但这是我所做的,继续前进。 – user4581301

+0

没有必要明确写入''类,因为[注入的类名]内(https://stackoverflow.com/questions/25549652/why-is-there-an-injected-class-name)。 –

回答

0

在班级体内定义这些功能并节省您的麻烦。另外,如果%的左侧操作数是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'; 
} 
1

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

你逃脱了operator <<我怀疑的原因,是你的问题,这使从<iostream>模板化operator <<声明中未示出using namespace std

这应该工作:

#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; 
} 
4

方法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

方法2

实现该类模板定义内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函数很复杂,则可以使用第一个方法并在类定义之外实现它们。

+0

谢谢。我想我现在在课堂上得到了真正的内容:上述声明的模板特化。而且由于'Number'的模板在它最终投入使用后会被专门化,所以我们应该能够在'Number'的定义之前再进一步闪避并完全定义模板化函数。这将会非常怪异,因为它现在看起来像我们在定义之前使用'Number'的一部分。 – user4581301

+0

@ user4581301,*那将是非常怪异的,因为它现在看起来我们正在使用已经被定义之前,他们数部分。*有(被称为[CRTP]的既定模式https://en.wikipedia.org/ wiki/Curiously_recurring_template_pattern)完全一样。 –

+1

更好一些,用一元运算符和/或方法实现二元运算符。那么你不需要他们成为朋友。 –

0

你可以让朋友操作模板化操作本身:

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