Speicher für verschiedenartige Methodenpointer
-
Hallo Leute,
ich schreibe gerade an einem programm in welchen ich ein datenhaltungsklasse (Daten) habe und ein klasse zur datenverwaltung (DataVectorCmd) (add, delete, edit...).
nun will ich das ganze so universell wie möglich gestalten.
ich möchte also in der DataVectorCmd eine methode haben (registerFctPtr) mit hilfe deren ich ein methodenpointer auf die get- und die set-methode von Daten setzen kann (weiterhin wird noch ein string mit einem beschreibenden namen übergeben).
nun ist meine frage wie ich die pointer und den namen am besten abspeichere. später möchte ich diese liste durchgehen und bsw. in der add-methode von DataVectorCmd die registrierten setter aufrufen und ein Datenobjekt befüllen.
schon mal vielen dank für eure antworten,
mfg sjoe
-
js schrieb:
nun ist meine frage wie ich die pointer und den namen am besten abspeichere
std::pair<std::string, boost::function<...> >
-
vielen dank für diese antwort,
ich habe mir jetzt mal das boost paket angeschaut. zum funktionieren gebracht habe ich es leider noch nicht. die beispiele aus dem tutorial haben funktioniert (boost sollte also korrekt installiert sein), aber meinen eigenen quelltext will es nicht schlucken.
hier mal der quelltext für die erstellung von "boostpointer"
boost::function<void (int)> sA; sA = &Daten::setAlter; boost::function<int (void)> gA; gA = &Daten::getAlter;und hier die dazu gehörige klasse
class Daten { private: string Name; int Alter; public: Daten(void); ~Daten(void); void setName(string n); string getName(void); void setAlter(int a); int getAlter(void); } ;also fehler kommt folgendes:
g++ -I"C:\Boost\include\boost-1_33_1" -O0 -g3 -Wall -c -fmessage-length=0 -oProjekt2.o ../Projekt2.cpp C:/Boost/include/boost-1_33_1/boost/function/function_template.hpp: In static member function `static void boost::detail::function::void_function_obj_invoker1<FunctionObj, R, T0>::invoke(boost::detail::function::any_pointer, T0) [with FunctionObj = boost::_mfi::mf1<void, Daten, int>, R = void, T0 = int]': C:/Boost/include/boost-1_33_1/boost/function/function_template.hpp:479: instantiated from `void boost::function1<R, T0, Allocator>::assign_to(FunctionObj, boost::detail::function::function_obj_tag) [with FunctionObj = boost::_mfi::mf1<void, Daten, int>, R = void, T0 = int, Allocator = std::allocator<void>]' C:/Boost/include/boost-1_33_1/boost/function/function_template.hpp:430: instantiated from `void boost::function1<R, T0, Allocator>::assign_to(Functor) [with Functor = boost::_mfi::mf1<void, Daten, int>, R = void, T0 = int, Allocator = std::allocator<void>]' C:/Boost/include/boost-1_33_1/boost/function/function_template.hpp:463: instantiated from `void boost::function1<R, T0, Allocator>::assign_to(MemberPtr, boost::detail::function::member_ptr_tag) [with MemberPtr = void (Daten::*)(int), R = void, T0 = int, Allocator = std::allocator<void>]' C:/Boost/include/boost-1_33_1/boost/function/function_template.hpp:430: instantiated from `void boost::function1<R, T0, Allocator>::assign_to(Functor) [with Functor = void (Daten::*)(int), R = void, T0 = int, Allocator = std::allocator<void>]' C:/Boost/include/boost-1_33_1/boost/function/function_template.hpp:294: instantiated from `boost::function1<R, T0, Allocator>::function1(Functor, boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = void (Daten::*)(int), R = void, T0 = int, Allocator = std::allocator<void>]' C:/Boost/include/boost-1_33_1/boost/function/function_template.hpp:638: instantiated from `boost::function<R ()(T0), Allocator>::function(Functor, boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = void (Daten::*)(int), R = void, T0 = int, Allocator = std::allocator<void>]' C:/Boost/include/boost-1_33_1/boost/function/function_template.hpp:666: instantiated from `boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R ()(T0), Allocator>&>::type boost::function<R ()(T0), Allocator>::operator=(Functor) [with Functor = void (Daten::*)(int), R = void, T0 = int, Allocator = std::allocator<void>]' ../Projekt2.cpp:32: instantiated from here C:/Boost/include/boost-1_33_1/boost/function/function_template.hpp:136: no match for call to `(boost::_mfi::mf1<void, Daten, int>) (int&)' C:/Boost/include/boost-1_33_1/boost/bind/mem_fn_template.hpp:148: candidates are: R boost::_mfi::mf1<R, T, A1>::operator()(T*, A1) const [with R = void, T = Daten, A1 = int] C:/Boost/include/boost-1_33_1/boost/bind/mem_fn_template.hpp:158: R boost::_mfi::mf1<R, T, A1>::operator()(T&, A1) const [with R = void, T = Daten, A1 = int]also kompiler benutze ich mingw.
gleich noch eine frage zu dem vorgeschlagenen code
std::pair<std::string, boost::function<...> >ich möchte ja letztendlich verschiedenartige pairs in einen vektor oder ähnlichem paken. bzw. in bezug auf meinen quelltext oben, möchte ich gA und sA in ein und die selbe liste, vektor... stecken. so das ich die liste später durchgehen kann und die funktionen aufrufen kann.
ist das mit dem pair möglich oder meckert der kompiler weilstd::pair<std::string, boost::function<void (int)> >und
std::pair<std::string, boost::function<int (void)> >verschiedene ausprägungen sind?
vielen dank,
sjoe
-
js schrieb:
ist das mit möglich?
Hallo sjoe,
ja das alles ist möglich, wenn man zeit hast
Ich hab für dich ein kleines Programmchen geschrieben. Versuch mal zu verstehen, wie es funktioniert.//BOOST #include <boost/bind.hpp> #include <boost/variant.hpp> //STL #include <vector> #include <map> #include <string> #include <iostream> using namespace std; class Daten { private: string Name; int Alter; public: Daten(string n, int a) : Name(n), Alter(a) { } void setName(string n) { Name = n; } string getName() const { return Name; } void setAlter(int a) { Alter = a; } int getAlter() const { return Alter; } struct Print { public: explicit Print(std::ostream &os) : os(os) { } void operator()(const Daten &d) const { os << "Daten( " << d.getName(); os << ", " << d.getAlter() << ")" << std::endl; } private: std::ostream &os; }; }; class MyDatenVector { typedef void (Daten::*FSetString)(string); typedef string (Daten::*FGetString) () const; typedef void (Daten::*FSetInt)(int); typedef int (Daten::*FGetInt)() const; typedef boost::variant<FSetString, FGetString, FSetInt, FGetInt> variant_func; std::vector<Daten> daten; std::map<string, variant_func> funcs; public: void print_all(std::ostream &os) { std::for_each(daten.begin(), daten.end(), Daten::Print(os)); } void push_back(const Daten &obj) { daten.push_back(obj); } void registerFctPtr(const string &name, variant_func func) { funcs[name] = func; } template<typename Value> void doSetForEach(const string &name, Value val) { //extract functor variant_func func = funcs[name]; typedef void (Daten::*FSetSign)(Value); FSetSign originFunc = boost::get<FSetSign>(func); //call for each std::for_each(daten.begin(), daten.end(), boost::bind(originFunc, _1, val)); } }; int main() { MyDatenVector myVec; myVec.push_back(Daten("Dirk", 30)); myVec.push_back(Daten("Kai", 25)); myVec.push_back(Daten("Anika", 20)); myVec.print_all(std::cout); myVec.registerFctPtr("SetName", &Daten::setName); myVec.registerFctPtr("GetName", &Daten::getName); myVec.registerFctPtr("SetAlter", &Daten::setAlter); myVec.registerFctPtr("GetAlter", &Daten::getAlter); myVec.doSetForEach("SetAlter", 12); std::cout << "\n\nAfter SetAlter\n"; myVec.print_all(std::cout); myVec.doSetForEach("SetName", string("Nixda")); std::cout << "\n\nAfter SetName\n"; myVec.print_all(std::cout); }MfG.
ssm
-
vielen dank ssm,
wenn ich mir die main function anschaue ist das eigentlich genau das was ich mir vorgestellt habe.
ich werde mal schauen ob ich das so in meinem programm umsetzen kann.mfg sjoe
-
hallo leute,
ein problem habe ich noch. und zwar soll die klasse daten nicht die ausgabe funktion enthalten (siehe quelltext von ssm). die ausgabe soll ebenfalls von MyDatenVector übernommen werden. mein gedanklicher hintergrund ist folgender, ich weiß nicht ob die datenspeicherobjekte "Daten" letztenendlich auf der console, einer windowsanwendung oder einem webinterface ausgegeben werden. deshalb verbietet es sich für mich die ausgabe dort zu realisieren.
ich habe mir überlegt ob es vielleicht mit rtti funktionieren könnte. und zwar könnte man doch der register-funktion den zubehandelnde datentype mitgeben.
template <class ObjectType> class MyDatenVector { // ... std::vector<ObjectType> daten; std::map<string, variant_func> funcs; // die funktionspointer std::map<string, const type_info* > types; // die funktionsrückgabetypen std::vector<string> funs; // die funktionsnamen // ... void registerFctPtr(const string &name, variant_func func, const type_info *type) { cout << "reg t: " << type->name() << endl; funcs[name] = func; types[name] = type; funs.push_back(name); } // ... } // ... int main() { MyDatenVector<Daten> myVec; // ... myVec.registerFctPtr("setName", &Daten::setName, &typeid(&Daten::setName)); myVec.registerFctPtr("getName", &Daten::getName, &typeid(&Daten::getName)); myVec.registerFctPtr("setAlter", &Daten::setAlter, &typeid(&Daten::setAlter)); myVec.registerFctPtr("getAlter", &Daten::getAlter, &typeid(&Daten::getAlter)); // ...bei der ausgabe müsste man nun die funktionen welche ja erstmal vom typ variant_func sind in den richtigen typ umwandeln. nur wie?
template <class ObjectType> class MyDatenVector { // ... void printDaten() { for(unsigned int i = 0; i!= daten.size(); i++) { for(unsigned int j = 0; j!= funs.size(); j++) { if(funs[j].substr(0, 3) == string("get")) { cout << "funcs: " << funs[j] << endl; variant_func func = funcs[funs[j]]; typedef void (ObjectType::*FGetSign)(); types[funs[j]] originFunc = boost::get<types[funs[j]]>(func); // hier irgendwie umwandeln cout << boost::bind(originFunc, &daten[i], _1)(); } } } } // ... } // ...also wenn ich die umwandlung hinbekommen würde wäre mein problem gelößt. für ideen, vorschläge oder anregungen wäre ich sehr dankbar.
eine gute nacht wünscht,
sjoe
-
Hallo js,
ist auch ganz einfach. So sieht das aus:
Output:
Object 008A3D48 Method name = getAlter, result = 30 Method name = getName, result = AAA Object 008A3D68 Method name = getAlter, result = 25 Method name = getName, result = SSS Object 008A3D88 Method name = getAlter, result = 20 Method name = getName, result = FFFSource Code
//BOOST #include <boost/bind.hpp> #include <boost/variant.hpp> //STL #include <vector> #include <map> #include <string> #include <iostream> using namespace std; class Daten { private: string Name; int Alter; public: Daten(string n, int a) : Name(n), Alter(a) { } void setName(string n) { Name = n; } string getName() const { return Name; } void setAlter(int a) { Alter = a; } int getAlter() const { return Alter; } }; class output_to_stream : public boost::static_visitor<std::ostream &> { public: output_to_stream(std::ostream &os, const Daten &daten) : os(os), daten(daten) { } template<typename T> std::ostream & operator()(T obj) const { assert(0 && "is not getter!!!"); return os; } template<typename T> std::ostream & operator()(T (Daten::*func)() const) const { return os << (daten.*func)(); } private: std::ostream &os; const Daten &daten; }; class MyDatenVector { typedef void (Daten::*FSetString)(string); typedef string (Daten::*FGetString) () const; typedef void (Daten::*FSetInt)(int); typedef int (Daten::*FGetInt)() const; typedef boost::variant<FGetString, FGetInt, FSetInt, FSetString> variant_func; std::vector<Daten> daten; std::map<string, variant_func> funcs; public: void push_back(const Daten &obj) { daten.push_back(obj); } void registerFctPtr(const string &name, variant_func func) { funcs[name] = func; } void printDaten() const { typedef std::vector<Daten>::const_iterator daten_citer; typedef std::map<string, variant_func>::const_iterator funcs_citer; daten_citer dit = daten.begin(), dend = daten.end(); while(dit != dend) { const Daten &obj = *dit; std::cout << "Object " << &obj << "\n"; funcs_citer fit = funcs.begin(), fend = funcs.end(); while(fit != fend) { const std::string &funcName = fit->first; if(funcName.substr(0, 3) == "get") { std::cout << "\tMethod name = " << funcName << ", "; std::cout << "result = "; boost::apply_visitor(output_to_stream(std::cout, obj))(fit->second); std::cout << std::endl; } ++fit; } ++dit; } } }; int main() { MyDatenVector myVec; myVec.push_back(Daten("AAA", 30)); myVec.push_back(Daten("SSS", 25)); myVec.push_back(Daten("FFF", 20)); myVec.registerFctPtr("setName", &Daten::setName); myVec.registerFctPtr("getName", &Daten::getName); myVec.registerFctPtr("setAlter", &Daten::setAlter); myVec.registerFctPtr("getAlter", &Daten::getAlter); myVec.printDaten(); }MfG.
ssm
-
fantastisch, die ausgabe funktioniert prima.
ich habe jetzt mal versucht das ganze auf eine eingabe zu adaptieren, leider funktioniert das ganze nicht so wie ich will.
template <class ObjectType> class stream_to_methode : public boost::static_visitor<> { private: std::istream &is; const ObjectType &in_obj; public: stream_to_methode(std::istream &is, const ObjectType &in_obj) : is(is), in_obj(in_obj) { } template <typename T> void operator()(void (ObjectType::*func)(T)) const { T t; is >> t; (in_obj.*func)(t); } };und der aufruf
template <class ObjectType> class MyDatenVector { //... void readDaten() const { typedef std::vector<ObjectType>::const_iterator daten_citer; typedef std::map<string, variant_func>::const_iterator funcs_citer; daten_citer dit = daten.begin(), dend = daten.end(); while(dit != dend) { const ObjectType &obj = *dit; std::cout << "Object " << &obj << "\n"; funcs_citer fit = funcs.begin(), fend = funcs.end(); while(fit != fend) { const std::string &funcName = fit->first; if(funcName.substr(0, 3) == "set") { std::cout << "\tMethod name = " << funcName << ", "; std::cout << "input: "; boost::apply_visitor(stream_to_methode<ObjectType>(std::cin, obj), fit->second); } ++fit; } ++dit; } } };vielleicht kannst du mir dazu nochmal einen tipp geben.
vielen dank schon mal im voraus,
sjoe
-
du hast fast alles richtig gemacht, weiter so!
so würde ich es machen:template <class ObjectType> class stream_to_methode : public boost::static_visitor<> { private: std::istream &is; /*!!!const*/ ObjectType &in_obj; public: stream_to_methode(std::istream &is, /*!!!const */ ObjectType &in_obj) : is(is), in_obj(in_obj) { } /*!!!*/ template<typename T> void operator()(T obj) const { assert(0 && "is not setter!!!"); } template <typename T> void operator()(void (ObjectType::*func)(T))/*!!!const */ { T t; is >> t; (in_obj.*func)(t); } };der aufruf:
void readDaten()/* !!! const */ { /*!!!*/ //typedef std::vector<ObjectType>::const_iterator daten_citer; typedef std::vector<ObjectType>::iterator daten_iter; typedef std::map<string, variant_func>::const_iterator funcs_citer; daten_iter dit = daten.begin(), dend = daten.end(); while(dit != dend) { /*!!!const */ObjectType &obj = *dit; std::cout << "Object " << &obj << "\n"; funcs_citer fit = funcs.begin(), fend = funcs.end(); while(fit != fend) { const std::string &funcName = fit->first; if(funcName.substr(0, 3) == "set") { std::cout << "\tMethod name = " << funcName << ", "; std::cout << "input: "; //!!! boost::apply_visitor(stream_to_methode<ObjectType>( std::cin, obj))(fit->second); } ++fit; } ++dit; } }Die Fehler hab ich mit "!!!" markiert.
-
hey,
was heisst da explicit? was macht das genau?
struct Print { public: explicit Print(std::ostream &os) : os(os) { }cu
-
hallo ssm,
also dein code funktioniert eigentlich gut. unter ms visual studio 2005 express, leider benutze ich aber eclipse mit cdt und mingw, also gnu.
dort will folgendes einfach nicht durch den compilerboost::apply_visitor(stream_to_methode<ObjectType>(std::cin, obj))(fit->second); // ... boost::apply_visitor(output_to_stream(std::cout, obj))(fit->second);ich habe es mal mit der ersatz konstruktion probiert
boost::apply_visitor(stream_to_methode<ObjectType>(std::cin, obj), fit->second); // ... boost::apply_visitor(output_to_stream(std::cout, obj), fit->second);für output_to_stream funktioniert es, aber für stream_to_methode leider nicht (0 && "is not setter!!!").
gibt es dafür ein workaround?
mfg sjoe
-
-mingw Version?
-BOOST Version
-Fehlermeldung?
-
serbi schrieb:
was heisst da explicit? was macht das genau?
-
-mingw Version?
-BOOST Version
-Fehlermeldung?schuldigung.
for(map<string, variant_func>::iterator iter = getter.begin(); iter != getter.end(); iter++) { cout << iter->first << ": "; boost::apply_visitor(output_to_stream<ObjectType>(cout, DV.at(pos)))(iter->second); // hm cout << endl; }die dritte zeile wird angemeckert. und zwar mit folgendem:
../DataVectorCmd.h:97: could not convert `output_to_stream<Daten>((&std::cout), (+(this + 24)->std::vector<_Tp, _Alloc>::at(unsigned int) [with _Tp = Daten, _Alloc = std::allocator<Daten>](pos)))' to `output_to_stream<Daten>&' C:/Boost/include/boost-1_33_1/boost/variant/detail/apply_visitor_delayed.hpp:79: in passing argument 1 of `boost::apply_visitor_delayed_t<Visitor> boost::apply_visitor(Visitor&) [with Visitor = output_to_stream<Daten>]'mingw version 3.2.3
boost version 1.33.1mfg sjoe
-
versuch mal so:
const ObjectType &myObj = DV.at(pos); output_to_stream<ObjectType> myVisitor(std::cout, myObj); variant_func myFunc = iter->second; boost::apply_visitor(myVisitor, myFunc);
-
spuer, funktioniert.
vielen dank,
sjoe
-
When a constructor is specified as explicit, no automatic conversion will be used with that constructor --it will only be used when an initialization exactly matches a call to that constructor.
was heisst das zu deutsch?
-
serbit schrieb:
was heisst das zu deutsch?
siehst du jetzt den Unterschied ?
class A { public: explicit A(const char *) { } }; class B { public: B(const char *) { } }; void foo1(const A &a) { } void foo2(const B &b) { } int main() { //------------------------------------------------------------------------- //error C2440: 'initializing' : cannot convert from 'const char [2]' to 'A' //A a = "!"; //OK! B b = "!"; //------------------------------------------------------------------------- //------------------------------------------------------------------------- //OK! A a1("!"); //OK! B b1("!"); //------------------------------------------------------------------------- //------------------------------------------------------------------------- //error C2664: 'foo1' : cannot convert parameter 1 from 'const char [2]' to 'const A &' //foo1("!"); //OK! foo2("!"); //------------------------------------------------------------------------- }