Seite 1 von 1

Template-Methoden-Spezialisierung

Verfasst: Mi Mai 09, 2012 11:00 am
von Xin
Moin!

Folgendes Beispiel:

Code: Alles auswählen

#include <stdio.h>

template<typename T>
class ref
{
  public:
  T * Reference;

  ref( T & reference );
};

template<typename T>
ref<T>::ref( T & reference )
    : Reference( &reference )
{
  printf( "Standard\n" );
}

template<>
ref<int>::ref( int & reference )
    : Reference( &reference )
{
  printf( "int-Spezialisierung\n" );
}


int main()
{
  double d;
  int i;
  ref<double> rdouble(d);
  ref<int>    rint(i);

  return 0;
}
Hier werden zwei Refs erzeugt, eins mit einem Double, das andere mit einem int. Für den Konstruktor für ref<int> gibt es eine Spezialisierung. Startet man das Programm kommt folgendes heraus:

Code: Alles auswählen

Standard
int-Spezialisierung
Soweit, so gewollt.

Nun brauche ich aber zwei Template-Parameter, wobei ich mich auf einen spezialisieren möchte:

Code: Alles auswählen

#include <stdio.h>

template<typename T, typename U>
class ref
{                                                               // Zeile 5
  public:
  T * Reference;
  U * URef;

  ref( T & reference, U & uref );                  // Zeile 10
};

template< typename T, typename U >
ref<T,U>::ref( T & reference, U & uref )
    : Reference( &reference )
    , URef( &uref )
{
    printf( "Standard\n" );
}


template< typename U >
ref<int, U>::ref( int & reference, U & uref )                    // Zeile 23
    : Reference( &reference )
    , URef( &uref )
{
    printf( "int\n" );
}                                                                    // Zeile 28


int main()
{
  double d1, d2, di;
  int i;

  ref< double, double > dref( d1, d2 );
  ref< int   , double > iref(  i, di );

  return 0;
}
Das hier kann ich nichtmals mehr kompilieren.

g++:

Code: Alles auswählen

uref2.cpp:23: error: invalid use of incomplete type 'class ref<int, U>'
uref2.cpp:5: error: declaration of 'class ref<int, U>'
Visual Studio 2010:

Code: Alles auswählen

1> uref2.cpp(28): error C2244: 'ref<T,U>::ref': Keine Übereinstimmung für Funktionsdefinition mit vorhandener Deklaration gefunden
1>          uref2.cpp(10): Siehe Deklaration von 'ref<T,U>::ref'
1>          Definition
1>          'ref<int,U>::ref(int &,U &)'
1>          Vorhandene Deklarationen
1>          'ref<T,U>::ref(T &,U &)'
Wie erkläre ich es meinem Compiler(n)?
Ich möchte nicht die komplette Template ref<> spezialisieren, da ich eigentlich nur eine einzige Methode (nichtmals den Konstruktor) spezialisieren muss.

Re: Template-Methoden-Spezialisierung

Verfasst: Mi Mai 09, 2012 12:23 pm
von Xin
Der VC2010 ist schonmal raus: "You cannot partially specialize a function template."

Jemand eine Ahnung, ob derartiges mit dem GNU machbar ist?

Re: Template-Methoden-Spezialisierung

Verfasst: Mi Mai 09, 2012 3:29 pm
von Kerli
Zumindest vom Standard ist teilweise Spezialisierung von Memberfunktionen nicht vorgesehen. Mit ein paar Metatemplate-Tricks ist es aber möglich den gewünschten Effekt zu erreichen (Mit C++11. Frühere Versionen brauchen eine eigene Implementierung von enable_if und is_integral, zb auch in Boost.TypeTraits):

Code: Alles auswählen

#include <stdio.h>
#include <type_traits>

template<typename T, typename U>
class ref
{
  public:
  T * Reference;
  U * URef;

  template<typename Dummy = T>
  ref(typename std::enable_if<std::is_integral<Dummy>::value, T>::type& reference, U& uref)
  {
    printf( "int\n" );
  }
  
  template<typename Dummy = T>
  ref(typename std::enable_if<!std::is_integral<Dummy>::value, T>::type& reference, U& uref)
  {
    printf( "Standard\n" );
  }
};

int main()
{
  double d1, d2, di;
  int i;

  ref< double, double > dref( d1, d2 );
  ref< int   , double > iref(  i, di );

  return 0;
}

Re: Template-Methoden-Spezialisierung

Verfasst: Mi Mai 09, 2012 3:44 pm
von Xin
Bahnhof?

Re: Template-Methoden-Spezialisierung

Verfasst: Mi Mai 09, 2012 3:50 pm
von fat-lobyte
Xin hat geschrieben:Bahnhof?
Geht nicht.

Workaround: enable_if verwenden.

Allgemeines Bespiel:

Code: Alles auswählen

template <typename T>
MeinStruct 
{
   T methode(const typename std::enable_if<std::is_integral<T, void>::type&);
};

int main()
{
  MeinStruct<int> s;
  s.(13); // geht, Funktionskopf wird zu "T methode(const int&)"
  
  MeinStruct<char*> t;
  t.("nein"); // geht nicht, da std::enable_if einen fehler produziert, und der overload vom compiler entfernt wird. Das nennt man SFINAE.
}
SFINAE: http://en.wikipedia.org/wiki/Substituti ... t_an_error

Konkretes Beispiel, siehe Kerlis post.

Re: Template-Methoden-Spezialisierung

Verfasst: Mi Mai 09, 2012 3:57 pm
von Xin
Ich habe mein Problem gelöst, indem ich im Container (U) eine allgemeine Methode für den fraglichen Datentyp T rufe und diese dann spezialisiert habe.

Alles andere muss ich mir mal genauer anlesen. Hübsch sieht das aber nicht aus... :-/