Forum: Compiler & IDEs Template-Funktion in Template-Klasse spezialisieren


von jgdo (Gast)


Lesenswert?

Hallo!

Folgende Klasse ist gegeben:
1
template<class T>
2
class C {
3
    template<class U>
4
    void foo(U u);
5
};

Nun möchte ich für alle möglichen T foo() für bestimmte U 
spezialisieren, z.b. für U = int:
1
template<>
2
template<class T>
3
void C<T>::foo<int>(int u) { ... }

Der Compiler (gcc) meldet
1
function template partial specialization 'foo<int>' is not allowed
 Ich verstehe jedoch nicht ganz, warum da 'partial' steht. Ich will ja 
für alle Template-Parameter von foo eine Spezialisierung machen.

Falls C selbst keine Template-Klasse ist, funktioniert das ganze.

Lässt sich mein Vorhaben irgendwie in C++ realisieren?

Grüße
- jgdo -

von Klaus W. (mfgkw)


Lesenswert?

sieht wohl schlecht aus...

von Klaus W. (mfgkw)


Lesenswert?

Was natürlich geht, ist für beide templates gleichzeitig zu 
spezialisieren:
1
template<>
2
template<>
3
void C<int>::foo<int>(int u)
4
{
5
  std::cout << "ok: " << u << std::endl;
6
}

Aber den Templateparameter für C offen lassen, wüsste ich nicht wie man 
das schreiben soll.

von drama (Gast)


Lesenswert?

AFAIR kann man nur teilweise spezialisieren, wenn es sich um die gleiche 
Art von Template-Parameter handelt. Wie soll das auch sonst 
funktionieren? Da müsste C++ bei dir ja eventuell "nachträglich" in eine 
existierende Klasse weitere überladene Funktionen einbauen. Warum machst 
du nicht einfach alles als Klassenparameter?

von drama (Gast)


Lesenswert?

Also z.B.
1
template<class T, class U>
2
class C {
3
    void foo(U u);
4
};

sollte doch eigentlich funktionieren.

von Ralf G. (ralg)


Lesenswert?

Ich hab' da möglicherweise was falsch verstanden, aber was ist an der 
'normalen' Variante so schlecht?
1
template<class T, class U>
2
class C
3
{
4
  T x;
5
    void foo(U u);
6
};
7
C<int,int> V;

Edit: Zu lange gebastelt.

: Bearbeitet durch User
von Fabian D. (fabian_d)


Lesenswert?

Dein Problem wird durch Funktionsüberladung gelöst. Dafür benötigst du 
keinen expliziten Templateparameter.

von Ralf G. (ralg)


Lesenswert?

Fabian Dreyersdorff schrieb:
> Dein Problem wird durch Funktionsüberladung gelöst.
Da musst du aber für jeden Typ eine Funktion schreiben. Das will man 
sich mit Templates ja sparen.

von jgdo (Gast)


Lesenswert?

Vielen dank für eure Anregungen!

drama schrieb:
> Warum machst
> du nicht einfach alles als Klassenparameter?

Weil ich innerhalb der gleichen C<T>-Klasse mehrere verschiedene 
foo<U>() aufrufen möchte.

Fabian Dreyersdorff schrieb:
> Dein Problem wird durch Funktionsüberladung gelöst. Dafür benötigst du
> keinen expliziten Templateparameter.

Ralf G. schrieb:
> Fabian Dreyersdorff schrieb:
>> Dein Problem wird durch Funktionsüberladung gelöst.
> Da musst du aber für jeden Typ eine Funktion schreiben. Das will man
> sich mit Templates ja sparen.

Das könnte man tatsächlich so machen, allerdings wäre es nicht ganz 
optimal. Was ich u.a. erreichen möchte, ist dass der Compiler einen 
Fehler erzeugt, sobald es keine Spezialisierung von foo<U>() für einen 
Typen gibt, d.h. es ist erwünscht (bzw. erforderlich), für jeden Typen 
eine eigene Spezialisierung zu schreiben. Problem bei 
Funkionsüberladungen wären jedoch implizite Umwandlungen. Wenn ich z.B. 
nur foo(double) definiert habe, es aber mit einem int aufrufe, würde der 
Compiler implizit den int nach double konvertieren und foo(double) 
aufrufen. Ich will jedoch, dass in diesem Fall das Programm nicht 
kompiliert, weil kein foo(int) definiert wurde.

Ich glaube das lässt sich lösen, indem man U in eine Box-Klasse packt. 
Dadurch würde das implizite Casten entfallen und man könnte 
Funktionsüberladungen anstatt der template-Methode nehmen.

- jgdo -

von Daniel A. (daniel-a)


Lesenswert?

Man kann inline template funktionen, template functiuns declarationen, 
überladung und default template parameter kombinieren, sollte den 
gleichen effekt haben wie dass, was du versuchst zu erreichen:
1
template<class T>
2
class C {
3
  private:
4
    template<class U>
5
    void foo(U);
6
  public:
7
    inline void foo(double x){
8
    }
9
    template<class U>
10
    inline void foo(U* x){
11
    }
12
};
13
14
int main(){
15
  C<int> c;
16
  c.foo(2.5); // ok
17
  c.foo(123); // error
18
  c.foo("test"); // ok
19
}

Aber wozu dass ganze?

von Fabian D. (fabian_d)


Lesenswert?

jgdo schrieb:
> Wenn ich z.B.
> nur foo(double) definiert habe, es aber mit einem int aufrufe, würde der
> Compiler implizit den int nach double konvertieren und foo(double)
> aufrufen. Ich will jedoch, dass in diesem Fall das Programm nicht
> kompiliert, weil kein foo(int) definiert wurde.

Hierfür könntest die Funktion ohne Funktionsrump deklarieren.
1
#include <iostream>
2
3
void func(int);
4
void func(double i) {
5
    std::cout << i;
6
}
7
8
int main(void) {
9
    func(5);
10
    return 0;
11
}

Der Kompiliervorgang scheitert an einem Linkererror:

g++ undefFunc.cpp -o undefined
/tmp/ccDqcvMI.o: In function `main':
undefFunc.cpp:(.text+0x30): undefined reference to `func(int)'
collect2: error: ld returned 1 exit status

Edit:
Ralf G. schrieb:
> Da musst du aber für jeden Typ eine Funktion schreiben. Das will man
> sich mit Templates ja sparen.
Funktionstemplates lassen sich aber nicht spezialisieren.

Mit C++11 geht es sogar noch eleganter mit einem echten Compiler-Fehler:
1
void func(double i) {
2
    std::cout << i;
3
}
4
5
template<typename T>
6
void func(T) = delete;

g++ undefFunc.cpp -std=c++11 -o undefined
undefFunc.cpp: In function ‘int main()’:
undefFunc.cpp:11:11: error: use of deleted function ‘void func(T) [with 
T = int]’
     func(5);
           ^
undefFunc.cpp:8:6: error: declared here
 void func(T) = delete;
      ^

Fabian

: Bearbeitet durch User
von Ralf G. (ralg)


Lesenswert?

jgdo schrieb:
> Nun möchte ich für alle möglichen T foo() für bestimmte U
> spezialisieren, z.b. für U = int:

Fabian Dreyersdorff schrieb:
> Funktionstemplates lassen sich aber nicht spezialisieren.

Ja, was soll hier denn 'spezialisieren' jetzt bedeuten?
a) in 'foo' über template überall den entsprechenden Typ eintragen? 
(Ansonsten ist der Inhalt der Funktion überall gleich)
oder
b) für jeden Typ soll eine vollkommen andere Funktion aufgerufen werden? 
(Gerne auch mit gleichem Namen) (*)

jgdo schrieb:
> Falls C selbst keine Template-Klasse ist, funktioniert das ganze.

Also, irgendwas passt für mich nicht zusammen ^^

Ralf G. schrieb:
> Ich hab' da möglicherweise was falsch verstanden, ...

(*) für b) würde ich noch 'pure virtual' in den Raum werfen, damit:
jgdo schrieb:
> Was ich u.a. erreichen möchte, ist dass der Compiler einen
> Fehler erzeugt, sobald es keine Spezialisierung von foo<U>() für einen
> Typen gibt, d.h. es ist erwünscht (bzw. erforderlich), für jeden Typen
> eine eigene Spezialisierung zu schreiben.

von ghl (Gast)


Lesenswert?

Daniel A. schrieb:
> Man kann inline template funktionen, template functiuns declarationen,
> überladung und default template parameter kombinieren, sollte den
> gleichen effekt haben wie dass, was du versuchst zu erreichen:

Wo sind denn da default template parameter?
Wenn du eine member function in der class declaration definierst 
brauchst du kein 'inline' - das ist implizit.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.