Templateクラス用のFriend Operator <<オーバーロード<<
-
09-10-2019 - |
質問
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...
}
}
他のヒント
そのような友人を宣言することはできません。そのために別のテンプレートタイプを指定する必要があります。
template <typename SclassT>
friend ostream& operator<< (ostream & os, const D<SclassT>& rhs);
ノート SclassT
それが影を落とさないように classT
. 。定義するとき
template <typename SclassT>
ostream& operator<< (ostream & os, const D<SclassT>& rhs)
{
// body..
}
これは、コンパイラの警告なしに私のために機能しました。
#include <iostream>
using namespace std;
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 {
return (d > rhs.d);
}
classT operator=(const D<classT>& rhs);
friend ostream& operator<< (ostream & os, const D& rhs) {
os << rhs.d;
return os;
}
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;
}
どうぞ:
#include <cstdlib>
#include <iostream>
using namespace std;
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 { return d > rhs.d;};
classT operator=(const D<classT>& rhs);
template<class classT> friend ostream& operator<< (ostream & os, const D<classT>& rhs);
private:
classT d;
};
template<class classT> ostream& operator<<(ostream& os, class D<typename classT> const& rhs)
{
os << rhs.d;
return os;
}
int main()
{
int i1 = 1;
int i2 = 2;
D<int> d1(i1);
D<int> d2(i2);
cout << my_max(d1,d2) << endl;
return 0;
}
そもそも友達になるべきではないと思います。
パブリックメソッドコールプリント、このようなもの(テンプレート以外のクラスの場合)を作成できます。
std::ostream& MyClass::print(std::ostream& os) const
{
os << "Private One" << privateOne_ << endl;
os << "Private Two" << privateTwo_ << endl;
os.flush();
return os;
}
そして、クラスの外側(ただし同じ名前空間で)
std::ostream& operator<<(std::ostream& os, const MyClass& myClass)
{
return myClass.print(os);
}
テンプレートクラスでも機能するはずだと思いますが、まだテストしていません。