Seite 1 von 2

Boost::Bind und std::for_each

Verfasst: Di Nov 08, 2011 1:03 am
von Bebu
Hallo, ich habe schon wieder ein Problem und kann den Fehler nicht finden( ich sollte aufhören so spät noch zu programmieren ;) )

Ein paar Dinge zur Klarheit:

Code: Alles auswählen

typedef Dedupe::Dataholding::Variant::Data * Value;
typedef std::map<std::string,Value> Row;
typedef std::vector<Row> Result;
ReturningTable ist ein Result nach obigem Code. Ich versuche diese Funktion hier

Code: Alles auswählen

Dedupe::FileStream Dataholding::FileGetter()
{
  Dedupe::FileStream ReturningStream;

  std::for_each( ReturningTable.begin(), ReturningTable.end(), boost::bind( Dataholding::TranslateSqlTableToFileInfo,  ReturningStream, _1 ) );

  return ReturningStream;
}

über boost::bind mit dieser Funktion

Code: Alles auswählen

static void TranslateSqlTableToFileInfo( SqliteWrapper::Row Incoming,
                                          Dedupe::FileStream Output );
zusammenzustöpseln, aber der Kompiler beschwert sich mit

Code: Alles auswählen

In file included from /usr/include/boost/bind.hpp:22:0,
                 from /home/bernhard/Programmieren/dedupe/trunk/dataholding/dataholding.h:13,
                 from /home/bernhard/Programmieren/dedupe/trunk/dataholding/dataholding.cpp:9:
/usr/include/boost/bind/bind.hpp: In member function ‘void boost::_bi::list2<A1, A2>::operator()(boost::_bi::type<void>, F&, A&, int) [with F = void (*)(std::map<std::basic_string<char>, Dedupe::Dataholding::Variant::Data*>, std::vector<Dedupe::FileInfo>), A = boost::_bi::list1<std::map<std::basic_string<char>, Dedupe::Dataholding::Variant::Data*>&>, A1 = boost::_bi::value<std::vector<Dedupe::FileInfo> >, A2 = boost::arg<1>]’:
/usr/include/boost/bind/bind_template.hpp:32:59:   instantiated from ‘boost::_bi::bind_t<R, F, L>::result_type boost::_bi::bind_t<R, F, L>::operator()(A1&) [with A1 = std::map<std::basic_string<char>, Dedupe::Dataholding::Variant::Data*>, R = void, F = void (*)(std::map<std::basic_string<char>, Dedupe::Dataholding::Variant::Data*>, std::vector<Dedupe::FileInfo>), L = boost::_bi::list2<boost::_bi::value<std::vector<Dedupe::FileInfo> >, boost::arg<1> >, boost::_bi::bind_t<R, F, L>::result_type = void]’
/usr/include/c++/4.6/bits/stl_algo.h:4379:2:   instantiated from ‘_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = __gnu_cxx::__normal_iterator<std::map<std::basic_string<char>, Dedupe::Dataholding::Variant::Data*>*, std::vector<std::map<std::basic_string<char>, Dedupe::Dataholding::Variant::Data*> > >, _Funct = boost::_bi::bind_t<void, void (*)(std::map<std::basic_string<char>, Dedupe::Dataholding::Variant::Data*>, std::vector<Dedupe::FileInfo>), boost::_bi::list2<boost::_bi::value<std::vector<Dedupe::FileInfo> >, boost::arg<1> > >]’
/home/bernhard/Programmieren/dedupe/trunk/dataholding/dataholding.cpp:95:142:   instantiated from here
/usr/include/boost/bind/bind.hpp:313:9: error: could not convert ‘(& a)->boost::_bi::list1<A1>::operator[] [with T = std::vector<Dedupe::FileInfo>, A1 = std::map<std::basic_string<char>, Dedupe::Dataholding::Variant::Data*>&]((* &((boost::_bi::list2<boost::_bi::value<std::vector<Dedupe::FileInfo> >, boost::arg<1> >*)this)->boost::_bi::list2<boost::_bi::value<std::vector<Dedupe::FileInfo> >, boost::arg<1> >::<anonymous>.boost::_bi::storage2<boost::_bi::value<std::vector<Dedupe::FileInfo> >, boost::arg<1> >::<anonymous>.boost::_bi::storage1<boost::_bi::value<std::vector<Dedupe::FileInfo> > >::a1_))’ from ‘std::vector<Dedupe::FileInfo>’ to ‘std::map<std::basic_string<char>, Dedupe::Dataholding::Variant::Data*>’
Jemand eine Idee, was ich diesmal wieder einfach nicht sehen kann. Wenn es wieder ein Klammer ist, dann kriege ich die Krise :evil:

Danke

Re: Boost::Bind und std::for_each

Verfasst: Di Nov 08, 2011 2:36 am
von fat-lobyte
Bebu hat geschrieben:Ich versuche diese Funktion hier

Code: Alles auswählen

Dedupe::FileStream Dataholding::FileGetter()
{
  Dedupe::FileStream ReturningStream;

  std::for_each( ReturningTable.begin(), ReturningTable.end(), boost::bind( Dataholding::TranslateSqlTableToFileInfo,  ReturningStream, _1 ) );

  return ReturningStream;
}
Die Syntax für Memberfunktionen sieht ein bisschen anders aus:

Code: Alles auswählen

#include <iostream>
#include <functional>

using namespace std::placeholders;

struct A {
    void member_a() {}
    int member_b(int x) { return x; }
    int member_c(int x, int y) { return x * y; }
};

int main()
{
    A a;

    auto ba = std::bind(&A::member_a, &a);
    auto bb = std::bind(&A::member_b, &a, _1);
    auto bc = std::bind(&A::member_c, &a, 4, _1);
    
    ba();
    std::cout<<"bb(2) = "<<bb(2)<<'\n';
    std::cout<<"bc(8) = "<<bc(8)<<'\n';
    
    return 0;
}
Erklärung: der Zeiger auf eine Memberfunktion ist &Klasse::member. Implizit wird bei jedem Memberaufruf der This-Zeiger übergeben, also muss man ihn hier auch angeben (und nicht die Referenz). Der Rest sollte gleich funktionieren.


ps.: An alle auto-Gegner: ich wünsche euch viel Spaß beim herausfinden des Types von ba, bb und bc :-)

Re: Boost::Bind und std::for_each

Verfasst: Di Nov 08, 2011 10:58 am
von Kerli
Wenn du die Funktion TranslateSqlTableToFileInfo nur einmal brauchst würde sich an dieser Stelle übrigens auch eine Lambdafunktion sehr gut anbieten...

Re: Boost::Bind und std::for_each

Verfasst: Di Nov 08, 2011 12:36 pm
von Bebu
Danke, aber ich bin noch nicht weiter. Lambda Funktionen muss ich mir erst mal ansehen, aber es kann sein, das die Translate Funktion zu unübersichtlich wird, wenn ich sie als Lambda schreibe. Ich habe jetzt die Signatur geändert auf:

Code: Alles auswählen

std::for_each( ReturningTable.begin(), ReturningTable.end(), boost::bind( &Dedupe::Dataholding::Dataholding::TranslateSqlTableToFileInfo, this, ReturningStream, _1 ) );
aber es will nicht :( Und denk dran, ich benutzte noch keine Features aus dem neuen Standard, sonst würde ich momentan viel zu viele Kompiler ausschließen. Darüber könnte man sich mal Gedanken machen, aber momentan bin ich beim "alten" C++. Das sind immer so einfache banale Fehler, aber ab einer bestimmten länge der Fehlermeldungen, bin ich immer überfordert, weil es total unübersichtlich wird. Hier die aktuelle Fehlermeldung:

Code: Alles auswählen

In file included from /usr/include/c++/4.6/algorithm:63:0,
                 from /home/bernhard/Programmieren/dedupe/trunk/filesearch/searchfiles.h:12,
                 from /home/bernhard/Programmieren/dedupe/trunk/dataholding/dataholding.h:11,
                 from /home/bernhard/Programmieren/dedupe/trunk/dataholding/dataholding.cpp:9:
/usr/include/c++/4.6/bits/stl_algo.h: In function ‘_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = __gnu_cxx::__normal_iterator<std::map<std::basic_string<char>, Dedupe::Dataholding::Variant::Data*>*, std::vector<std::map<std::basic_string<char>, Dedupe::Dataholding::Variant::Data*> > >, _Funct = boost::_bi::bind_t<boost::_bi::unspecified, void (*)(std::map<std::basic_string<char>, Dedupe::Dataholding::Variant::Data*>, std::vector<Dedupe::FileInfo>), boost::_bi::list3<boost::_bi::value<Dedupe::Dataholding::Dataholding*>, boost::_bi::value<std::vector<Dedupe::FileInfo> >, boost::arg<1> > >]’:
/home/bernhard/Programmieren/dedupe/trunk/dataholding/dataholding.cpp:95:169:   instantiated from here
/usr/include/c++/4.6/bits/stl_algo.h:4379:2: error: no match for call to ‘(boost::_bi::bind_t<boost::_bi::unspecified, void (*)(std::map<std::basic_string<char>, Dedupe::Dataholding::Variant::Data*>, std::vector<Dedupe::FileInfo>), boost::_bi::list3<boost::_bi::value<Dedupe::Dataholding::Dataholding*>, boost::_bi::value<std::vector<Dedupe::FileInfo> >, boost::arg<1> > >) (std::map<std::basic_string<char>, Dedupe::Dataholding::Variant::Data*>&)’
Und ich dachte noch, die Datenhaltung wird keine große Sache und ist schnell geschrieben... theoretisch...

Re: Boost::Bind und std::for_each

Verfasst: Di Nov 08, 2011 1:08 pm
von Kerli
Statische Memberfunktionen brauchen keinen this-Zeiger. Sie haben ja schließlich nichts mit einer speziellen Instanz zu tun sondern werden immer ohne Objekt aufgerufen.

Re: Boost::Bind und std::for_each

Verfasst: Di Nov 08, 2011 1:34 pm
von Bebu
So jetzt kann mich die ganze Sache mal gerne haben:

Code: Alles auswählen

Dedupe::FileStream Dataholding::FileGetter()
{
  Dedupe::FileStream ReturningStream;

  BOOST_FOREACH( Dedupe::Dataholding::SqliteWrapper::Row row, ReturningTable )
  {
    TranslateSqlTableToFileInfo( row, ReturningStream );
  }
  return ReturningStream;
}
Soll bind doch machen was es will :evil:

Re: Boost::Bind und std::for_each

Verfasst: Di Nov 08, 2011 1:42 pm
von fat-lobyte
Bebu hat geschrieben:Soll bind doch machen was es will :evil:
Auch ne Lösung :-) Mit neuem C++ sowieso keine Probleme mehr. Übrigens glaube ich, dass du bei den typen noch ein paar probleme hast. Theoretisch ist es schon möglich ich hab schon ein paar boost::bind aufrufe geschafft :-)

Und tut mir leid mit dem this-Zeiger, da hab ich dich in die Irre geführt weil ich was falsch verstanden habe.

Re: Boost::Bind und std::for_each

Verfasst: Di Nov 08, 2011 1:49 pm
von Bebu
Danke, aber es hat ohne this Zeiger auch nicht funktioniert. Naja, ich denke die Lösung oben ist sowieso schöner zu lesen.
Wie meinst du das mit den Typen?

Re: Boost::Bind und std::for_each

Verfasst: Di Nov 08, 2011 2:00 pm
von fat-lobyte
Könntest du bitte die Signatur von Dedupe::Dataholding::Dataholding::TranslateSqlTableToFileInfo() posten?

[edit]
sorry, Leseverständnis-fail.
Versuchs mal damit:

Code: Alles auswählen

std::for_each(
    ReturningTable.begin(),
    ReturningTable.end(), 
    boost::bind( 
        &Dedupe::Dataholding::Dataholding::TranslateSqlTableToFileInfo, 
        _1, ReturningStream) 
);
Das argument SqliteWrapper::Row Incoming ist das erste, also musst du es bind auch als erstes angeben. Dedupe::FileStream Output ist das zweite, es kommt als zweites. Das "_1" bezieht sich darauf, dass es im erstellten funktionsobjekt das erste argument sein wird. Der This-zeiger ist weg, da die methode ja statisch ist (sorry wegen der Verwirrung).


ps.: Ein hübscher Indentation-Style hilft bei solchen Monster-Boost-STL-STL-Aufrufen ungemein. Du musst meinen nicht kopieren, aber ich empfehle dir lange Aufrufe nicht in eine einzige Zeile zu quetschen.

Re: Boost::Bind und std::for_each

Verfasst: Di Nov 08, 2011 10:30 pm
von Bebu
fat-lobyte hat geschrieben: Versuchs mal damit:

Code: Alles auswählen

std::for_each(
    ReturningTable.begin(),
    ReturningTable.end(), 
    boost::bind( 
        &Dedupe::Dataholding::Dataholding::TranslateSqlTableToFileInfo, 
        _1, ReturningStream) 
);
Werde ich machen, sobald ich wieder an meinem eigenen Computer sitze, auf diesem hier, habe ich gerade nicht alles nötige da. Obwohl mir optisch die andere Lösung sowieso besser gefällt. Ich meine allerdings deinen Vorschlag schon selber getestet zu haben, aber ich probiere es noch einmal.
fat-lobyte hat geschrieben: ps.: Ein hübscher Indentation-Style hilft bei solchen Monster-Boost-STL-STL-Aufrufen ungemein. Du musst meinen nicht kopieren, aber ich empfehle dir lange Aufrufe nicht in eine einzige Zeile zu quetschen.
Meinst du die Codezeile? Du hast recht, obwohl es nicht meine Art ist, alles in eine Zeile zu quetschen, ich versuche schon sinnvoll zu trennen und mich auch an die 80 Zeichen Breite zu halten. Allerdings ist das oft sehr knapp und man muss manchmal schon Sachen trennen, die man gar nicht trennen will, vor allem, wenn die Namensräume schon etwas länger sind...