Template-Funktion in Template-Klasse spezialisieren

Gast #3966623
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 -
#3966754
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.
Gast #3966759
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?
Gast #3967256
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 -
#3967306
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?
#3969075
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
#3969133
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.
Gast #3976903
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren