下記をg++(fedora core1)でコンパイルしたところ、
#include <iostream>
using namespace std;
template< typename T > class A {
T a;
public:
A(T aa ) : a(aa) { }
friend ostream& operator<<( ostream &os, const A &a ); //9行目
};
template< typename T >
ostream& operator<<( ostream &os, const A<T> &a ) { return os << a.a; }
int main( )
{
A<int> a(5);
cout << a << '\n';
return 0;
}
9行目にこのような警告・エラーが出てコンパイルできませんでした。(下記のオプションも試してみましたがダメでした)
friend declaration 'std::ostream& operator<<(std::ostream&, const A<T>&)' declares a non-template function
(if this is not what you intended, make sure the function template has already been declared and add<> after the function name here)
-Wno-non-template-friend disables this warning.
:undefined reference to 'operator<<(std::basic_ostream <char, std::char_traits<char> >&, A<int> const&)'
なぜ、コンパイルできないのかが分かりません。ちなみに、bcc32(borland c++ compiler5.5.1)では同様のエラーが出てコンパイルできず、cl(VC++6.0)ではコンパイル・実行可能でした。
ご存知の方いらっしゃったらご教授お願いします。(bccとclはWinXPです)
No.2ベストアンサー
- 回答日時:
リンクエラーになるのは、テンプレート関数のインスタンス化ができないからです。
テンプレート関数は、それが使用されているいずれかの場所において、その定義も行われていなければなりません。これは通常の関数が定義と同時にコードが生成されるのと異なり、テンプレート関数はT<int>などと実際にテンプレート引数が決まったときにしかコードが生成できないためです。この点について、テンプレートはインライン関数と似たような性質を持っています。
この制約のため、テンプレート関数は宣言と定義が併記されることが非常に多いです。STLなどもそうです。
これを回避する方法として、"明示的な実体化"という手法があります。これはテンプレート引数を決定したテンプレート関数の実体を予め生成してしまう手段です。実体がコードとして存在するようになるため、リンクエラーにならなくなります。詳しくは調べてください。
ありがとうございます。フレンドクラスやテンプレート等のそれぞれについては手元の書籍を読み進めましたが、これらを混ぜて応用しようとするとうまくできません。さらに勉強したいと思います。
No.1
- 回答日時:
friend ostream& operator<<( ostream &os, const A<T> &a ); //9行目
としておかないと、構文上は確かに、エラーですね。テンプレートクラスのフレンド関数は、暗黙のテンプレート関数とはなりません。(これに対して、メンバー関数は、暗黙のうちに、そのクラスのテンプレート引数を持つテンプレート関数となります。)
ですから、Aという型は存在しないということになりますので、A<T>と宣言してやる必要があります。
ところが、bcc32ですと、こうしても、まだエラーになります。今度は、リンクエラーで、このテンプレート関数を認識してくれないのです。実験してみた限りでは、おそらく、ostreamがらみのtypedefがいたずらしていると思われますが、そこまでは解析しきれませんでした。
回避方法は、public関数として、printなりなんなりのメンバー関数を定義して、これを外部の非フレンドの大域テンプレート関数から呼び出す形にしてあげるとなぜかすべて順調にいきます。
ありがとうございます。ご回答を参考にしましていろいろ試したところ、
template<typename T> class A {
/* ... */
public:
friend void print_classA( const A<T> &a ); //{ cout << a.a; } <-- 定義もする
};
template< typename T >
void print_classA( const A<T> &a ) { cout << a.a; }
としてもエラーになりますが、コメントのように宣言と定義を同じ場所でするとコンパイル・実行ともに可能でした。テンプレートクラスのフレンド関数は、宣言と定義を別の場所にすると互いを結びつけることができないとも思えますが、手元の書籍を調べてもはっきりとは分かりませんでした。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C++プログラミングコードにポリモーフィズムを取り入れ方を教えてください。 2 2023/06/09 11:17
- C言語・C++・C# C++初心者です stirng 2 2022/09/20 20:43
- C言語・C++・C# C++のcinの動作 5 2023/02/26 00:13
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- C言語・C++・C# メインプログラムに#include <algorithm>を書いて、 そのメインプログラムが // 3 2023/05/02 11:24
- C言語・C++・C# スタックフレームの消滅 6 2023/05/20 12:33
- その他(プログラミング・Web制作) Texに詳しい方よろしくお願いいたします 2 2023/01/16 22:25
- C言語・C++・C# Cのdoubleの浮動小数点表示について 3 2023/04/17 13:14
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
End Sub が必要です。
-
pythonの条件分岐(if)
-
対応する関数ヘッダーがありません
-
構造体のポインタ参照
-
43:syntax error at end of input
-
Makefile と <math.h>
-
intel fortranのエラーで困って...
-
フォートラン(fortran)のエラー...
-
Delphiでif文がうまく書けないです
-
HEW3とBorlandC++でクラス定義...
-
python numpy.linalg.inv()での...
-
STL mapでアクセス違反
-
#ifndefとかヘッダファイルにつ...
-
Excel・Word リサーチ機能を無...
-
特定のPCだけ動作しないVBAマク...
-
配列数式の解除
-
エクセルで特定の列が0表示の場...
-
メッセージボックスのOKボタ...
-
Excel マクロ VBA プロシー...
-
教えて下さい
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
End Sub が必要です。
-
pythonの条件分岐(if)
-
Excel VABについて 下記記述が...
-
43:syntax error at end of input
-
フォートランのエラーについて...
-
intel fortranのエラーで困って...
-
他クラスからForm1内コントロル...
-
Excel VBA: UserForm.Show で実...
-
AccessVBAでVLookupを使いたい
-
対応する関数ヘッダーがありません
-
VB2005でOCXを動的に呼び出すに...
-
C# IEnumerable が IEnumerable...
-
ラズパイ上の、pythonのエラー...
-
コンパイルで未定義のシンボル
-
select関数の使用方法について
-
HEW3とBorlandC++でクラス定義...
-
構造体のポインタ参照
-
VB.NETのStructureの使い方を教...
-
waveOutProc関数での定義
-
フォートラン(fortran)のエラー...
おすすめ情報