Frage

Ich habe einige Fragen in Bezug auf mein Problem auf StackOverflow.com liest jetzt, und nichts davon scheint mein Problem zu lösen. Oder ich vielleicht getan haben es falsch ... Der überladene << funktioniert, wenn ich es in eine Inline-Funktion machen. Aber wie mache ich es in meinem Fall arbeiten?

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

Der Code:

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;
}
War es hilfreich?

Lösung

Dies ist eine jener häufig gestellte Fragen, die unterschiedliche Ansätze haben, die ähnlich sind, aber nicht wirklich das gleiche. Die drei Ansätze unterscheiden sich in die erklären Sie, ein Freund von Ihrer Funktion sein --und dann auf, wie Sie es umsetzen.

Die extrovertierte

Deklarieren Sie alle Instanzen der Vorlage als Freunde. Dies ist, was Sie als Antwort akzeptiert haben, und auch, was die meisten anderen Antworten vorschlagen. Bei diesem Ansatz öffnen Sie unnötig Ihre spezielle Instantiierung D<T> von Freunden aller operator<< instantiations erklärt. Das heißt, std::ostream& operator<<( std::ostream &, const D<int>& ) hat Zugriff auf alle Interna von 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
}

Die introvertierten

erklärt nur eine bestimmte Instanziierung des Einfügeoperator als Freund. D<int> kann den Einfügeoperator wie wenn sich aufgebracht, aber es will nichts mit std::ostream& operator<<( std::ostream&, const D<double>& ) zu tun.

Dies kann auf zwei Arten erfolgen, die einfache Art und Weise ist, wie @Emery Berger vorgeschlagen, die die Bediener inlining --which auch aus anderen Gründen eine gute Idee ist:

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>
   }
};

In dieser ersten Version, Sie sind nicht ein Templat operator<< zu schaffen, sondern eine nicht-Templat-Funktion für jede Ausprägung der Test Vorlage. Auch hier ist der Unterschied subtil, aber das ist im Grunde gleichwertig manuell hinzufügen. std::ostream& operator<<( std::ostream&, const Test<int>& ) wenn Sie instantiate Test<int> und andere ähnliche Überlastung, wenn Sie instantiate Test mit double, oder mit jeder anderen Art

Die dritte Version ist umständlicher. Ohne inlining den Code, und mit der Verwendung einer Vorlage können Sie einen einzelnen Instanziierung der Vorlage ein Freund der Klasse deklarieren, ohne Öffnen Sie sich zu alle andere instantiations:

// 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> ...
}

Unter Ausnutzung des extrovertierten

Der feine Unterschied zwischen dieser dritten Option und das ist zunächst, wie viel Sie zu anderen Klassen eröffnen. Ein Beispiel für Missbrauch in der extrovertiert Version jemand sein würde, die den Zugang in die Interna bekommen will und tut dies:

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...
   }
}

Andere Tipps

Sie können einen Freund wie das erklären, müssen Sie dafür eine andere Vorlage Typ angeben.

template <typename SclassT>
friend ostream& operator<< (ostream & os, const D<SclassT>& rhs);

note SclassT so dass es Schatten nicht classT. Bei der Definition

template <typename SclassT>
ostream& operator<< (ostream & os, const D<SclassT>& rhs)
{
  // body..
}

Das ist für mich ohne Compiler-Warnungen gearbeitet.

#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;
}

Hier gehen Sie:

#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;
}

Ich glaube, Sie sollten nicht Freund an erster Stelle machen.

Sie können eine öffentliche Methode Anruf Druck, so etwas wie dies schaffen (für eine nicht Template-Klasse):

std::ostream& MyClass::print(std::ostream& os) const
{
  os << "Private One" << privateOne_ << endl;
  os << "Private Two" << privateTwo_ << endl;
  os.flush();
  return os;
}

und dann außerhalb der Klasse (aber im gleichen Namensraum)

std::ostream& operator<<(std::ostream& os, const MyClass& myClass)
{
  return myClass.print(os);
}

ich denke, es sollte auch für die Template-Klasse arbeiten, aber ich noch nicht getestet haben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top