template classのfriend関数をクラス内部で実装する

テンプレートクラスを作成し、その演算子などを非メンバ関数で定義する場合
往々にして、friend関数にする場合が多いと思います

これが厄介で、まずテンプレートクラスの前方宣言をします
その後にテンプレート関数として目的のfriend関数を前方宣言します
次にテンプレートクラス内部で目的の関数をfriend関数宣言をします
最後にテンプレートクラス外部で実装を書きます

friend関数をいたるところに書いてやる必要があります

// classの前方宣言
template <typename T>
class Obj;

// friend関数の前方宣言
template <typename T>
std::ostream& operator<<(std::ostream&,const Obj<T>& t);

// class実装
template <typename T>
class Obj
{
private:
    T t_;
public:
    Obj(T t) : t_(t) { }
    Obj()=default;
    
    // friend関数指定
    //   template<typename U> 
    //   friend std::ostream& operator<< (std::ostream&,const Obj<U>&); // ベタ書き
    friend std::ostream& operator<< <T>(std::ostream&,const Obj<T>&);  // すこし簡略化
};
// friend関数の実装
template <typename T>
std::ostream& operator<< (std::ostream& o,const Obj<T>& t) 
{ 
    return o << t.t_;
}

うわぁ・・・ めんどくさいですね

と、思っていたのですが、もっとスマートに書く方法がありました

template <typename T>
class Obj
{
private:
    T t_;
public:
    Obj(T t) : t_(t) { }
    Obj()=default;

    //friend関数指定も実装も全部まとめて書ける。前方宣言もいらない
    friend std::ostream& operator<< (std::ostream& o,const Obj& t)
    { 
        return o << t.t_;
    }
};

http://melpon.org/wandbox/permlink/vvT6OT7PsGGAShBW

こんなふうに書けるのは知りませんでした

これで関数前言をばら撒かなくてよくなりました!
やったね!

参考:
http://web.mst.edu/~nmjxv3/articles/templates.html