Ciao a tutti, sto leggendo una guida sul C++ e sono arrivato ai template. Per fare una prova, ho fatto questa classe:

codice:
template <int _N> class Zn
{
    int _val;
    int _mod(int n){ return (n>=0) ? (n % _N) : (_N - ( (-n) % _N))%_N; }

    public:
        Zn(){ _val = 0; }
        Zn(int n){ _val = _mod(n); }
        Zn operator +(Zn b){ return Zn(_val + b._val); }
        Zn operator -(Zn b);
        int getN(){ return _N; }
        int getval(){ return _val; }
};

template <int _N> Zn<_N> Zn<_N>::operator -(Zn<_N> b)
{
    return Zn(_val - b._val);
}
dove ho scritto il + in modo inline, e il - in modo espanso (tutto corretto?)
Ora, volevo aggiungere il << per stampare a video, ma dovendo fare una funzione friend, non ho idea della sintassi (che sul libro non c'è scritta in questo caso specifico).
Quello che avevo pensato "inventando a senso" era:

codice:
template <int _N> class Zn
{
    int _val;
    int _mod(int n){ return (n>=0) ? (n % _N) : (_N - ( (-n) % _N))%_N; }

    public:
        Zn(){ _val = 0; }
        Zn(int n){ _val = _mod(n); }
        Zn operator +(Zn b){ return Zn(_val + b._val); }
        Zn operator -(Zn b);
        int getN(){ return _N; }
        int getval(){ return _val; }

        template <int _N> friend ostream &operator <<(ostream &stream, Zn<_N> o);
};

template <int _N> Zn<_N> Zn<_N>::operator -(Zn<_N> b)
{
    return Zn(_val - b._val);
}

template <int _N> ostream &operator <<(ostream &stream, Zn<_N> o)
{
    stream << o._val;
    return stream;
}
che però non compila, sembra che il <int _N> nel caso di una funzione membro viene preso quello della classe, nel caso di una funzione non membro viene "ridefinito", e infatti il compilatore mi segnala una duplicazione di _N... e allora ho modificato così:

codice:
template <int _N> class Zn
{
    int _val;
    int _mod(int n){ return (n>=0) ? (n % _N) : (_N - ( (-n) % _N))%_N; }

    public:
        Zn(){ _val = 0; }
        Zn(int n){ _val = _mod(n); }
        Zn operator +(Zn b){ return Zn(_val + b._val); }
        Zn operator -(Zn b);
        int getN(){ return _N; }
        int getval(){ return _val; }

        template <int __N> friend ostream &operator <<(ostream &stream, Zn<__N> o);
};

template <int _N> Zn<_N> Zn<_N>::operator -(Zn<_N> b)
{
    return Zn(_val - b._val);
}

template <int __N> ostream &operator <<(ostream &stream, Zn<__N> o)
{
    stream << o._val;
    return stream;
}
e così funziona tutto. Ho inoltre anche aggiunto il + tra due classi diverse, facendo:
codice:
#include <iostream>


using namespace std;

template <int _N> class Zn
{
    int _val;
    int _mod(int n){ return (n>=0) ? (n % _N) : (_N - ( (-n) % _N))%_N; }

    public:
        Zn(){ _val = 0; }
        Zn(int n){ _val = _mod(n); }
        Zn operator +(Zn b){ return Zn(_val + b._val); }
        Zn operator -(Zn b);
        int getN(){ return _N; }
        int getval(){ return _val; }

        template <int __N> friend ostream &operator <<(ostream &stream, Zn<__N> o);

        template <int __N1, int __N2> friend Zn<__N1> operator +(Zn<__N1> o1, Zn<__N2> o2);
};

template <int _N> Zn<_N> Zn<_N>::operator -(Zn<_N> b)
{
    return Zn(_val - b._val);
}

template <int __N> ostream &operator <<(ostream &stream, Zn<__N> o)
{
    stream << o._val;
    return stream;
}

template <int __N1, int __N2> Zn<__N1> operator +(Zn<__N1> o1, Zn<__N2> o2)
{
    return Zn<__N1>(o1._val + o2._val);
}
e anche questa cosa funziona.

La mia domanda è: è giusto quello che ho scritto, visto che l'ho "inventato"? C'è un modo migliore?

Grazie!