2017-10-28 10 views
2

私は、テンプレートクラスのfriend関数を記述したいと思います。 ビジュアルスタジオでは、私は両方の事前定義を無視することができます。 しかし、g ++では必須です。 なぜですか?なぜg ++はテンプレートクラスとそのfriend関数の両方の定義を必要としますか?

#include <iostream> 
using namespace std; 
// g++ needs, vs do not needs 
template <class T> 
class A; 

template <class T> 
ostream & operator<<(ostream & c, const A<T> & v); 
//- end of g++ needs 

template <class T> 
class A { 
    T _v; 
public: 
    A() {} 
    A(T v) : _v(v) {} 
    friend ostream & operator<<<T>(ostream & c, const A<T> & v); 
}; 
template <class T> 
ostream & operator<<(ostream & c, const A<T> & v) { 
    c << v._v; return c; 
} 
+0

私の最高の推測では、Visual Studioはg ++より少しだけあなたを助けてくれます。皮肉なことに、g ++はエラー記述をコンパイルするのに適しているようです。私が "ヘルプ"を意味するのは、コードが 'File.txt'をタイプしたときにVSが' file.txt'を開いたときですが、g ++はファイルが存在せず、開くこともできないと言いました。 –

+0

g ++では、 'friend'関数の宣言(または定義?)にプロトタイプが必要です。プロトタイプを作成するには、テンプレートクラスの前方宣言が必要です。これをg ++で一度学んだら、私のコードはVS _without_で動作していたことを最近疑問に思っていました(しかし、私は深く掘り下げませんでした)。 (ご質問ありがとうございます) – Scheff

+0

@BrianW私は、 'file.txt'と' File.txt'に関するあなたの言及した例は、単にOSの問題であると信じています。 Windowsでは、ファイル名は大文字と小文字を区別しないで扱われます。 Linuxでは、もちろんファイル名は大文字と小文字が区別されます(ただし、システム関数を使用していない場合は、アプリケーションによっても破損する可能性があります)。しかし、一般的に私はあなたに同意します:VSははるかに緩慢です(便利ですか?)。私たちがWindows/VSで開発したLinux/g ++にアプリケーションを移植すると、私はいつもこの問題に巻き込まれます(私たちは常に移植可能なコードを作ろうとします)。 – Scheff

答えて

2

friend ostream & operator<<<T>(ostream & c, const A<T> & v); 

は、あなたが最初と

A<T> 

部分は、あなたがあまりにも前にあることを宣言しなければならないことを意味することを宣言する必要が

template <class T> 
ostream & operator<<(ostream & c, const A<T> & v); 

の専門であるため、オペレータ宣言

template <class T> 
class A; 

だから、VSは、例えば、あなたの例では、第三friend宣言に合う

template<class T> class task; 
template<class T> task<T>* preempt(task<T>*); 

template<class T> class task { 
    friend void next_time(); 
    friend void process(task<T>*); 
    friend task<T>* preempt<T>(task<T>*); 
    template<class C> friend int func(C); 

    friend class task<int>; 
    template<class P> friend class frd; 
}; 

を与えるC++14

14.5.4 Friends [temp.friend] 

として、おそらく間違っています。

+0

ありがとう@Surt! –

0

MSVCテンプレートコードは根本的に壊れています。彼らはここ数年の間にそれを再建してきましたが、あなたが見ているもののような奇妙なものを含んでいます。これは、C++の標準ではなく、ほぼマクロ的に構築されているためです。あなたはクラスのボディに<<オペレータをインラインで定義することにより、前方宣言と離れて行うことができますgccので

friend std::ostream& operator<<(std::ostream& c, const A& v){ 
    c << v._v; 
    return c; 
} 

これは<<はもはやtemplateになるという利点を持っているのではなく、明確なテンプレートの各インスタンスに対して非テンプレートが作成されますA。いくつかのシナリオでは、これはうまくいく傾向があります。

+0

ありがとう@ヤク! –

関連する問題