テンプレートクラスでフレンド演算子<<をオーバーロードする
質問
私は今StackOverflow.comで私の問題についてのいくつかの質問を読みましたが、そのうちのどれも私の問題を解決していないようです。または私はそれを間違っていたかもしれません...
オーバーロードされた
<<
は、私がそれをインライン関数にした場合、動作します。でも、私の場合はどうすれば動くのでしょうか?
warning: friend declaration std::ostream& operator<<(std::ostream&, const D<classT>&)' declares a non-template function
warning: (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
/tmp/cc6VTWdv.o:uppgift4.cc:(.text+0x180): undefined reference to operator<<(std::basic_ostream<char, std::char_traits<char> >&, D<int> const&)' collect2: ld returned 1 exit status
コードです。
template <class T>
T my_max(T a, T b)
{
if(a > b)
return a;
else
return b;
}
template <class classT>
class D
{
public:
D(classT in)
: d(in) {};
bool operator>(const D& rhs) const;
classT operator=(const D<classT>& rhs);
friend ostream& operator<< (ostream & os, const D<classT>& rhs);
private:
classT d;
};
int main()
{
int i1 = 1;
int i2 = 2;
D<int> d1(i1);
D<int> d2(i2);
cout << my_max(d1,d2) << endl;
return 0;
}
template <class classT>
ostream& operator<<(ostream &os, const D<classT>& rhs)
{
os << rhs.d;
return os;
}
どのように解決するのですか?
これはよくある質問の1つで、似ているようで実は同じではない、さまざまなアプローチがあります。3 つのアプローチは、関数の友人であることを誰に宣言するか、そしてそれをどのように実装するかが異なります。
外向的なアプローチ
テンプレートのすべてのインスタンスを友人として宣言します。これは、あなたが回答として受け入れたものであり、また、他の回答のほとんどが提案しているものです。このアプローチでは、特定のインスタンスを不必要に開くことになります。
D<T>
を友人と宣言することで、すべての
operator<<
のインスタンス化です。つまり
std::ostream& operator<<( std::ostream &, const D<int>& )
のすべての内部にアクセスすることができます。
D<double>
.
template <typename T>
class Test {
template <typename U> // all instantiations of this template are my friends
friend std::ostream& operator<<( std::ostream&, const Test<U>& );
};
template <typename T>
std::ostream& operator<<( std::ostream& o, const Test<T>& ) {
// Can access all Test<int>, Test<double>... regardless of what T is
}
内向的な人
挿入演算子の特定のインスタンスのみを友人として宣言します。
D<int>
は自分自身に適用される挿入演算子を好むかもしれませんが、それは
std::ostream& operator<<( std::ostream&, const D<double>& )
.
これは2つの方法で行うことができます。簡単な方法は @Emery Berger が提案したように、演算子をインライン化することです --これは他の理由からも良いアイデアです。
template <typename T>
class Test {
friend std::ostream& operator<<( std::ostream& o, const Test& t ) {
// can access the enclosing Test. If T is int, it cannot access Test<double>
}
};
この最初のバージョンでは、あなたは
ではなく
を作成し、テンプレート化された
operator<<
のインスタンス化に対してテンプレート化されていない関数を作成するのではありません。
Test
テンプレートを使用します。繰り返しますが、違いは微妙ですが、これは基本的に手動で追加するのと同じです。
std::ostream& operator<<( std::ostream&, const Test<int>& )
をインスタンス化するときに
Test<int>
をインスタンス化するとき、また別の同様のオーバーロードをするとき
Test
で
double
または他の型と
3番目のバージョンはより面倒です。コードをインライン化せず、テンプレートを使用することで、テンプレートの単一のインスタンス化をクラスの友人として宣言することができます。 すべて 他のインスタンス化に対して自分自身を開くことなく、テンプレートの単一のインスタンスをあなたのクラスの友人と宣言することができます。
// Forward declare both templates:
template <typename T> class Test;
template <typename T> std::ostream& operator<<( std::ostream&, const Test<T>& );
// Declare the actual templates:
template <typename T>
class Test {
friend std::ostream& operator<< <T>( std::ostream&, const Test<T>& );
};
// Implement the operator
template <typename T>
std::ostream& operator<<( std::ostream& o, const Test<T>& t ) {
// Can only access Test<T> for the same T as is instantiating, that is:
// if T is int, this template cannot access Test<double>, Test<char> ...
}
外向的な性格を利用する
この3つ目の選択肢と1つ目の選択肢の微妙な違いは、他のクラスに対してどれだけオープンにしているかということにあります。の悪用例です。 外向型 バージョンでの悪用の例としては、あなたの内部へのアクセスを取得したい誰かがこれを実行することです。
namespace hacker {
struct unique {}; // Create a new unique type to avoid breaking ODR
template <>
std::ostream& operator<< <unique>( std::ostream&, const Test<unique>& )
{
// if Test<T> is an extrovert, I can access and modify *any* Test<T>!!!
// if Test<T> is an introvert, then I can only mess up with Test<unique>
// which is just not so much fun...
}
}
関連
-
[解決済み】LLVMで暗黙のうちに削除されたコピーコンストラクタの呼び出し
-
[解決済み】C++でユーザー入力を待つ【重複あり
-
[解決済み] string does not name a type Errorが発生するのはなぜですか?
-
[解決済み】「corrupted size vs. prev_size」glibc エラーを理解する。
-
[解決済み】c++でstd::vectorを返すための効率的な方法
-
[解決済み】Visual Studio 2013および2015でC++コンパイラーエラーC2280「削除された関数を参照しようとした」が発生する
-
[解決済み] to_string は std のメンバーではない、と g++ が言っている (mingw)
-
[解決済み】VC++の致命的なエラーLNK1168:書き込みのためにfilename.exeを開くことができません。
-
[解決済み] スタックアロケーションにより初期化されていない値が作成された
-
[解決済み】C/C++の"-->"演算子とは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C++コンパイルタイムエラー:数値定数の前に期待される識別子
-
[解決済み】C++でランダムな2倍数を生成する
-
[解決済み】関数名の前に期待されるイニシャライザー
-
[解決済み】「corrupted size vs. prev_size」glibc エラーを理解する。
-
[解決済み] 数値定数の前にunqualified-idを付けて、数値を定義することを期待する。
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み】デバッグアサーションに失敗しました
-
[解決済み] 配列のベクトルを扱う正しい方法
-
[解決済み】c++で.txtファイルから2次元の配列に読み込む
-
[解決済み] friend宣言がテンプレート以外の関数を宣言している [重複] 。