Container mit Zeigern und STL-Funktionstemplates
-
Danke, ich wollte aber eigentlich auf folgenden allgemeinen Fall hinaus, dass auch Argumente übergeben können ( Stroustrup, S.555-556):
class Object { void doSomething() { } }; void for_all_doSomething( std::list<Object*>& list ) { std::for_each(list.begin(), list.end(), mem_fun(&Object::doSomething)) } void main() { std::list<Object*> list; for_all_doSomething( ); }
Bei mir läuft dieser Code aber nicht.
-
for_all_doSomething( );
Du musst hier list als Parameter übergeben, sonst kann es nicht gehen! Wenn es das nicht ist, dann poste mal ein ausführbares Minimalbeispiel und die Fehlermeldung!
-
OK, ich habe es mit folgendem Code ausprobiert, funktioniert aber nicht:
object.h
#if !defined (__OBJECT_H__) #define __OBJECT_H__ #include <iostream> class Object { static int s_iIndex; int m_iIndex; public: Object() : m_iIndex (s_iIndex++) { } virtual ~Object() { } void print() const { std::cout << m_iIndex << std::endl; } }; class ObjectIterator { public: void objectIterator (const Object* o ) { o->print(); } }; int Object::s_iIndex = 0; #endif
main.cpp
#include "Object.h" #include <list> #include <algorithm> void main() { std::list<Object*> list; for( int i=0; i<10; ++i ) list.push_back( new Object() ); std::for_each( list.begin(), list.end(), ObjectIterator::objectIterator ); }
Als Fehlermeldung kommt:
main.cpp
\microsoft visual studio\vc98\include\algorithm(37) :
error C2064: Ausdruck ergibt keine Funktion\For_Each_Test\src\main.cpp(14) : Siehe Verweis auf Instantiierung der kompilierten Funktionsvorlage 'void (__thiscall ObjectIterator::*__cdecl std::for_each(class std::list<class Object *,class
std::allocator<class Object *> >::iterator,class std::list<class Object *,class std::allocator<class Object > >::iterator,void (__thiscall ObjectIterator::)(const class Object *)))(const class Object *)'
-
1.die funktion muss statisch sein, da sie sonst über ein objekt der klasse ObjectIterator aufgerufen werden muss.
2.#if !defined (__OBJECT_H__) #define __OBJECT_H__
ist ganz schlechter stil, der underscore mit nachfolgendem großbuchstaben, bzw der double underscore ist dem compiler und der stl vorbehalten.
besser so:
#ifndef object_h #define object_h
void main()
das ist vorsintflutlich!
besser:int main()
-
Luca76 schrieb:
OK, ich habe es mit folgendem Code ausprobiert, funktioniert aber nicht:
[...]std::for_each( list.begin(), list.end(), ObjectIterator::objectIterator ); }
Der Aufruf ergibt keinerlei sinn. ObjectIterator::objectIterator ist kein gültiges C++. Ich schätze mal du willst hier die Adresse der Memberfunktion objectIterator bilden. Dafür fehlt der unäre Operator &
std::for_each( list.begin(), list.end(), &ObjectIterator::objectIterator );
Das wiederum ergibt in diesem Kontext keinen Sinn. Ein Methodenzeiger ist alleine nicht aufrufbar. for_each versucht aber für jedes Element der angegebenen Sequenz das über den dritten Parameter gegebene Funktionsobjekt aufzurufen.
Ich weiß ehrlich gesagt nicht was genau du machen willst, aber wenn du ObjectIterator als Funktionsobjekt einsetzen willst, dann geht das so:class ObjectIterator { public: void operator() (const Object* o ) const { o->print(); } };
Der Aufruf sieht dann so aus:
std::for_each( list.begin(), list.end(), ObjectIterator() );
Wieso aber dann nicht gleich die print-Methode von Object benutzen?
#include <list> #include <algorithm> #include <functional> int main() { ... std::for_each( list.begin(), list.end(), std::mem_fun(&Object::print) ); }
-
std::mem_fun(&Object::print)
Wie funktioniert denn das? Woher kriegt std::mem_fun denn den Zeiger auf die Klasse?
-
Sorry. Meinte den Zeiger auf das Objekt...
-
Neulings schrieb:
std::mem_fun(&Object::print)
Wie funktioniert denn das? Woher kriegt std::mem_fun denn den Zeiger auf die Klasse?
mem_fun wandelt einen Aufruf der Form f(param) in die Form param->f().
Die Objekte sind in diesem Fall also nacheinander die Elemente der Liste.
-
Danke für die Hinweise.
HumeSikkins schrieb:
#include <list> #include <algorithm> #include <functional> int main() { ... std::for_each( list.begin(), list.end(), std::mem_fun(&Object::print) ); }
Ich habe es jetzt so probiert, nur leider kommt jetzt der Fehler:
functional(233) : error C2562: '()' : 'void'-Funktion gibt einen Wert zurueck
functional(232) : Siehe Deklaration von '()'
functional(233) : Bei der Kompilierung der Member-Funktion 'void __thiscall std::mem_fun_t<void,class Object>::operator ()(class Objectconst' der Klassenvorlage
Was ist jetzt noch falsch?
-
Luca76 schrieb:
Was ist jetzt noch falsch?
Dein Compiler. Der ist leider nicht ganz richtig in der Birne und in diesem Punkt meilenweit vom Standard entfernt.
In diesem Fall bleiben dir nur zwei Möglichkeiten:
1. Du gehst den Umweg über ein zusätzliches Funktionsobjekt (siehe Beispiel)
2. Du spendierst deiner print-Methode einen Rückgabewert und machsts sie non-const.
-
Visual C++ 6 habe ich.
-
Dein Compiler. Der ist leider nicht ganz richtig in der Birne und in diesem Punkt meilenweit vom Standard entfernt.
manno bin ich froooooooooo
dass ichVisual C++ 6
nicht mehr hab
-
Luca76 schrieb:
Visual C++ 6 habe ich.
man erkennt die qualität von C++ büchern daran, ob auf der cd ne autoren version von Vc6 ist^^
-
Luca76 schrieb:
Visual C++ 6 habe ich.
Wenn's dich beruhigt, ich benutze ebenfalls hauptsächlich diesen Compiler
Was du als drittes machen könntest, wäre auf eine andere STL-Implementation umzusteigen. STLPort ist z.B. ganz schön.
Als Übergangslösung würde ich auf jeden Fall die Variante mit dem zusätzlichen Funktionsobjekt verwenden.
-
Danke!
Habe STLport heruntergeladen, installiert und es funktioniert jetzt auch.
-
Wenn's dich beruhigt, ich benutze ebenfalls hauptsächlich diesen Compiler
Darf man fragen wieso? Verwendet ihr den bei euch an der Uni?
-
Helium schrieb:
Wenn's dich beruhigt, ich benutze ebenfalls hauptsächlich diesen Compiler
Darf man fragen wieso? Verwendet ihr den bei euch an der Uni?
Ja und nein. In unserem Informatikbereich wird hauptsächlich SunOS und Linux eingesetzt, demzufolge wird dort der gcc verwendet. Am HPI (Softwaresystemtechnik) wird hingegen eigentlich immer das neuste von Microsoft benutzt, sprich derzeit hauptsächlich Visual Studio .Net.
Das ich den VC 6.0 benutze hat drei entscheidene Gründe:
1. Ich bin Windows-Benutzer (komme mit Linux nach wie vor nicht zurecht).
2. Ich habe nach wie vor Windows98 installiert, kann also die Ganze .NET-Geschichten nicht so ohne weiteres einsetzen.
3. Die IDE des VC 6.0 (ergänzt um einige Plugins) ist meiner Meinung nach nach wie vor herausragend. Unter Berücksichtigung von 1. und 2. habe ich bisher nichts vergleichbares gesehen.Ich habe natürlich auch andere Compiler auf dem Rechner installiert (Win-Version des gcc, Cygwin + gcc sowie auch ein Linux mit immer aktuellem gcc), so dass ich auch mal problemlos mit Templates rumspielen kann. Für die normale Arbeit verwende ich aber immer den VC 6.0
-
So, ich wollte es jetzt auch mal so ausprobieren, dass ein Parameter übergeben werden kann.
class Object { public: void print( const std::string& msg ) { std::cout << msg; } }; int main( int argc, char *argv[] ) { std::list<Object*> objectList; std::string msg( "Ausgabe" ); std::for_each( objectList.begin(), objectList.end(), std::bind2nd( std::mem_fun(&Object::print), msg ) ); return 0; }
Beim Compilieren kommt dann der Fehler:
\stlport-4.6.2\stlport\stl\_function.h(166) : warning C4181: Auf Referenztyp angewendeter Qualifizierer wird ignoriert
\Test_Project\src\main.cpp(52) : Siehe Verweis auf Instantiierung der kompilierten Klassenvorlage '_STL::binder2nd<class _STL::mem_fun1_t<void,class Object,class _STL::basic_string<char,s
truct std::char_traits<char>,class _STL::allocator<char> > const &> >'
\stlport-4.6.2\stlport\stl\_function.h(165) : error C2529: '<unbekannt>' : Verweis auf Verweis ungueltig
\Test_Project\src\main.cpp(52) : Siehe Verweis auf Instantiierung der kompilierten Klassenvorlage '_STL::binder2nd<class _STL::mem_fun1_t<void,class Object,class _STL::basic_string<char,s
truct std::char_traits<char>,class _STL::allocator<char> > const &> >'Kann man eigentlich auch 2 Parameter übergeben?
-
Hallo,
dieses Referenz-auf-Referenz-Problem ist eine bekannte Schwäche für die es leider innerhalb der STL keine schöne Lösung gibt. Dazu müsste man Traits-Verwenden, was in der STL bisher leider nicht vorgesehen ist.Entweder du steigst auf sowas wie boost::bind um oder du musst den Parameter by value übergeben.
-
HumeSikkins schrieb:
Hallo,
Entweder du steigst auf sowas wie boost::bind um oder du musst den Parameter by value übergeben.Und, wie würde es dann aussehen?