2017-05-29 1 views
3

私はテンプレートクラスNumberを作成しました。 < <演算子がオーバーロードされましたが、%演算子を使用できません。テンプレートクラスに%operatorをオーバーロードするにはどうすればよいですか?

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未解決の外部"エラーが発生します。私の問題は2つの質問でまとめられます。 1.フレンド表記を使用して演算子をオーバーロードすると、なぜ<を使用する必要がありますか? 2.なぜ%演算子で動作しないのですか?

+1

ダーン良い質問です。私は良い答えがありません。あなたはテンプレートよりもはるかに優れている人が必要ですが、関数定義をクラスに移すと問題が解消することが分かります。 'friend number 演算子%(数字、数字b) { 戻り番号(%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

まず、演算子を関数テンプレートとして宣言してから、クラス内で "befriending"する必要があります。適切に行う方法の詳細については、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パラメータが使用されていることを確認してください。

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、*これは、私たちが定義される前にNumberの部分を使用しているように見えるので、本当に奇妙なことです。* [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についての説明を参照してください。

関連する問題