[template] functor
-
pumuckl schrieb:
Oehm nein. Der Template-Parameter ist ein Zeiger namens Member, der auf einen int innerhalb der Klasse namens Klasse zeigt. Dein Beispiel wuerde so aussehen
Du hast recht, es ist kein "Methodenzeiger", sondern ein "Memberzeiger". An dem Rest halte ich jedoch fest (ändert ja nichts daran dass ein Zeiger auf ein float-Member immernoch ein konstanter Zeiger und damit ein gültiger Templateparameter ist).
-
Gut, mein missverstaendnis. Nach genauerem Nachlesen schein muffmolch CStolls Besipiel als int-Parameter verstanden zu haben und nicht als member-pointer-to-int.
CStolls Antwirt gibt aber dann eigentlich alles was noetig ist, abgesehn von einer kleinen Unschoenheit: Es wird Information wiederholt, naemlich ueber die Klasse und ueber den Zieltyp des Pointers. Es muesste einen Mechanismus geben, um aus dem Pointer allein die Klasse und den Zieltyp zu extrahieren, so dass die Angabe von K und M unnoetig ist.Nur wie?

-
nein ich hatte es genau so verstanden, wie CStoll geschrieben hat. pointer auf ein int-member... laßt mich da raus

-
*alles zurueck nehm* Bin ja schon still

-
@pumuckl: schon okay.
dann sollte das ganze auch mit get-Methoden funktionieren, wenn man eh nur Funktionspointer übermittelt. Sehe ich das richtig? also wenn z.B. kein direkter Zugriff auf die Member klasse möglich ist und man die friend deklaierung vermeiden möchte:
class Klasse { public: ... double getVal1(); double getVal2(); ... private: double val1,val2;also in etwas so:
template<typename K, typename M, M (K::*fct)> struct compare { bool operator()(const K&r,const K&l) { return r.*fct< l.*fct; } }; sort(l.begin(),l.end(),compare<Klasse, &Klasse::getVal1>());
-
muffmolch schrieb:
template<typename K, typename M, M (K::*fct)()> //die Klammern hinten machen den unterschied zwischen Funktion und normalem Member struct compare { bool operator()(const K&r,const K&l) { return r.(*fct)()< l.(*fct)(); } //hier bedeuten die Klammern den Aufruf des opertor(), im Funktionspointer-Fall also der entsprechenden Funktion };Da fehlten Funktionsklammern an 3 Stellen, sonst duerfte es aber so funktionieren.
-
@pumuckl: Ja, ich hätte mir auch gewünscht, das alles auf einen Parameter zu reduzieren, aber das gibt C++ nicht her. Und eine Hilfsfunktion wie LordJaxom's CompareVal() lässt sich auch nicht einsetzen, weil nicht-Typ Parameter nur beschränkt erkannt werden können.
-
CStoll schrieb:
@pumuckl: Ja, ich hätte mir auch gewünscht, das alles auf einen Parameter zu reduzieren, aber das gibt C++ nicht her.
Wartmal. geht nicht sowas:
template <class C, typename M> sruct compare { typedef M C::*MemPtr; compare(MemPtr ptr) : mp_(ptr); bool operator()(C& l, C& r) {return l.(*mp_) < m.(*mp_);} private: MemPtr mp_; }; template <class C, typename M> //template argument deduction compare<C,M> make_compare(M C::*ptr) {compare<C,M> cmp(ptr); return cmp} sort(l.begin(),l.end(),make_compare(&Klasse::Member));Wupp, schon muesste es gehn...
-
Und um das Ganze noch etwas voranzutreiben:
template<class C, typename E> struct fkt_compare { typedef M C::(*MemFktPtr)(); compare(MemFktPtr ptr) : mfp_(ptr); bool operator()(C& l, C& r) {return l.(*mp_)() < m.(*mp_)();} private: MemPtr mfp_; }; template <class C, typename M> //template argument deduction again fkt_compare<C,M> make_compare(M C::(*ptr)()) {fkt_compare<C,M> fcmp(ptr); return fcmp}Damit kann make_compare auch ein Funktionspointer uebergeben werden, gleichzeitiges Ueberladen von Funktionstemplate mit template argument deduction

-
Ja, das geht - und das hat LordJaxom schon genannt. Bei meiner Variante ist es allerdings nicht so einfach, die argument deduction auszunutzen, weil der letzte Parameter nicht zur Compilezeit ermittelt werden kann (und
template<M K::*Member>...scheitert aran, daß der Compiler M und K nicht kennt).
-
@CStoll: meinst du das?
class Klasse{ public: Klasse(int val1, int val2 ) : val1(val1),val2(val2) {} // int getVal1() const { return val1; } // int getVal2() const { return val2; } //private: int val1, val2; }; template<typename K, typename M, M (K::*Member)> struct compareMember { bool operator()(const K &r, const K &l) { return r.*Member < l.*Member; } }; int main(){ list<Klasse> l; l.push_back(Klasse(10,10)); l.push_back(Klasse(1,5)); l.push_back(Klasse(50,3)); sort(l.begin(),l.end(),compareMember<Klasse, int, &Klasse::val1>()); };endet in folgendes compilerfehlermeldungen:
C:\Program Files\Microsoft Visual Studio 8\VC\include\algorithm(3261) : error C2784: 'reverse_iterator<_RanIt>::difference_type std::operator -(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'std::list<_Ty>::_Iterator<_Secure_validation>'
with
[
_Ty=Klasse,
_Secure_validation=true
]
C:\Program Files\Microsoft Visual Studio 8\VC\include\xutility(1856) : see declaration of 'std::operator -'
F:\LBM_subversion\source\lbmd2q9\a2pII\testcases\inputfileSerial\main.cpp(57) : see reference to function template instantiation 'void std::sort<std::list<_Ty>::_Iterator<_Secure_validation>,compareMember<K,M,Member>>(_RanIt,_RanIt,_Pr)' being compiled
with
[
_Ty=Klasse,
_Secure_validation=true,
K=Klasse,
M=int,
Member=pointer-to-member(0x0),
_RanIt=std::list<Klasse>::_Iterator<true>,
_Pr=compareMember<Klasse,int,pointer-to-member(0x0)>
]
C:\Program Files\Microsoft Visual Studio 8\VC\include\algorithm(3261) : error C2784: 'reverse_iterator<_RanIt>::difference_type std::operator -(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'std::list<_Ty>::_Iterator<_Secure_validation>'
with
[
_Ty=Klasse,
_Secure_validation=true
]
C:\Program Files\Microsoft Visual Studio 8\VC\include\xutility(1856) : see declaration of 'std::operator -'
C:\Program Files\Microsoft Visual Studio 8\VC\include\algorithm(3261) : error C2784: 'reverse_iterator<_RanIt>::difference_type std::operator -(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'std::list<_Ty>::_Iterator<_Secure_validation>'
with
[
_Ty=Klasse,
_Secure_validation=true
]
C:\Program Files\Microsoft Visual Studio 8\VC\include\xutility(1856) : see declaration of 'std::operator -'
C:\Program Files\Microsoft Visual Studio 8\VC\include\algorithm(3261) : error C2784: 'reverse_iterator<_RanIt>::difference_type std::operator -(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'std::list<_Ty>::_Iterator<_Secure_validation>'
with
[
_Ty=Klasse,
_Secure_validation=true
]
C:\Program Files\Microsoft Visual Studio 8\VC\include\xutility(1856) : see declaration of 'std::operator -'
C:\Program Files\Microsoft Visual Studio 8\VC\include\algorithm(3261) : error C2676: binary '-' : 'std::list<_Ty>::_Iterator<_Secure_validation>' does not define this operator or a conversion to a type acceptable to the predefined operator
with
[
_Ty=Klasse,
_Secure_validation=true
]
C:\Program Files\Microsoft Visual Studio 8\VC\include\algorithm(3261) : error C2780: 'void std::_Sort(_RanIt,_RanIt,_Diff)' : expects 3 arguments - 4 provided
C:\Program Files\Microsoft Visual Studio 8\VC\include\algorithm(3085) : see declaration of 'std::_Sort'
-
sort() erwartet Random-Access-Iteratoren, aber list<> hat "nur" bidirektionale Iteratoren (und der Compiler scheitert dabei, einen operator- für list-Iteratoren zu finden).
Also entweder du verwendest einen anderen Container (vector<> oder deque<>) oder du nutzt die list-Methode sort():
l.sort(compareMember<Klasse, int, &Klasse::val1>());
-
ich vollhonk... klaro... war vor lauter deduction ganz verwirrt...
-
okay. mit den membern klappt es nun. sehr gut. aber der methoden vergleich scheitert noch:
class Klasse{ public: Klasse(double val1, double val2 ) : val1(val1),val2(val2) {} double getVal1() const { return val1; } double getVal2() { return val2; } private: double val1, val2; }; template<typename K, typename M, M (K::*fct)()> struct compareMethods{ bool operator()(const K& r, const K& l) { return r.(*fct)() < l.(*fct)(); } }; int main(int argc, char** argv) { list<Klasse> l; l.push_back(Klasse(10,10)); l.push_back(Klasse(1,5)); l.sort(compareMethods<Klasse, double, &Klasse::getVal1 >() ); l.sort(compareMethods<Klasse, double, &Klasse::getVal2 >() ); }Fehler:
//Fuer l.sort( compareMethods<Klasse, double, &Klasse::getVal1 >() ):
1>main.cpp error C2440: 'specialization' : cannot convert from 'overloaded-function' to 'double (__thiscall Klasse::* )(void)'
//Fuer l.sort(compareMethods<Klasse, double, &Klasse::getVal2 >() ):
1>main.cpp error C2059: syntax error : '(' bei { return r.(*fct)() < l.(*fct)(); 1>while compiling class template member function 'bool compareMethods<K,M,fct>::operator ()(const K &,const K &)'
1> with
1> [
1> K=Klasse,
1> M=double,
1> fct=Klasse::getVal2
1> ]
1>main.cpp (56) : see reference to class template instantiation 'compareMethods<K,M,fct>' being compiled
1> with
1> [
1> K=Klasse,
1> M=double,
1> fct=Klasse::getVal2
1> ]
-
Zum ersten Fall: <ratemodus>fct ist ein Pointer zu einer non-const Funktion. Ich vermute, dass der Compiler Probleme damit hat, ihn mit einen const K anzuwenden. template<...., M (K::*fct)() const> oder sowas in der Art koennte evtl. helfen </ratemodus>
Zum zweiten Fall: Die Klammern um *fct waren Bloedsinn von mir. Dadurch wird der Member-Pointer_Zugriffsoperator .* zerlegt. Mein Fehler, sry...
alsoreturn r.*fct() < l.*fct();
-
auch nach der entfernung der klammern: gleicher fehler...
-
Gnarf ^^
hab mal in mein schlaues buch geschut, da wurden pointer-to-mem-fun's so aufgerufen:return (r.*fct)() < (l.*fct)();Vermutlich muss der linke AUsdruck geklammert werden, damit er erst dessen Rueckgabewert bestimmt (naemlich die Funktion fuer ein spezielles Obejkt), und danach erst den operator() drauf anwendet...
-
kannst du es dann kompilieren? denn dann bekomme ich diesen Fehler:
error C2440: 'argument' : cannot convert from 'const Klasse *' to 'Klasse *const '
Conversion loses qualifiers
-
Wo hast Du das const hingepackt? Folgendes Beispiel kompiliert hier: (Änderungen zu Deinem letzten vollständigen Beispiel sind markiert)
class Klasse { public: Klasse(double val1, double val2 ) : val1(val1),val2(val2) {} double getVal1() const { return val1; } double getVal2() const { return val2; } // <- hier const private: double val1, val2; }; template<typename K, typename M, M (K::*fct)() const> // <- hier const struct compareMethods { bool operator()(const K& r, const K& l) const // <- hier const (zwar nicht zwingend notwendig, aber eleganter) { return (r.*fct)() < (l.*fct)(); } // <- Klammersetzung }; using namespace std; int main(int argc, char** argv) { list<Klasse> l; l.push_back(Klasse(10,10)); l.push_back(Klasse(1,5)); l.sort( compareMethods<Klasse, double, &Klasse::getVal1 >() ); l.sort( compareMethods<Klasse, double, &Klasse::getVal2 >() ); }
-
so funktionierts. leider kann ich grad nicht sagen, woran es bei mir gehapert hat. Danke @all.