template < int X >
class Foo
{
  //ストリーム演算子をfriend宣言
  template < int X >
  friend std::ostream & operator << ( std::ostream & out, Foo<X> const & val ) ;
  
private :
  //実際の出力は、このメンバ関数が行う。
  void print( std::ostream & out ) const { out << "private!" ; };
} ;

template < int X >
std::ostream & operator << ( std::ostream & out, Foo<X> const & val )
{
  val.print(out) ;
  return out ;
}

int main( )
{
  Foo<1> f ;
  std::cout << f << std::endl ;
}

上記のコードを、VC8でコンパイルすると、
 >C2593: 'operator <<' があいまいです。
と言われてしまいます。
どうも、friend宣言も関数の定義と解釈しているようなのですが。
Barton and Nackman trickを使えば、なんとか意図通りのことができるのですが、
これは仕方がないのでしょうか?