2010-02-22 17 views
8

Mam mapę, która przechowuje prosty struct z kluczem. Struktura ma dwie funkcje składowe, jedna jest stała, a druga nie. Udało mi się wywołać funkcję const używając std :: for_each bez żadnych problemów, ale mam pewne problemy z wywołaniem funkcji non-const.Boost.Bind dostęp do elementów std :: map w std :: for_each

struct MyStruct { 
    void someConstFunction() const; 
    void someFunction(); 
}; 

typedef std::map<int, MyStruct> MyMap; 
MyMap theMap; 

//call the const member function 
std::for_each(theMap.begin(), theMap.end(), 
    boost::bind(&MyStruct::someConstFunction, boost::bind(&MyMap::value_type::second, _1))); 

//call the non-const member function 
std::for_each(theMap.begin(), theMap.end(), 
    boost::bind(&MyStruct::someFunction, boost::bind(&MyMap::value_type::second, _1))); 

Wywołanie funkcji członka const działa dobrze, ale wydaje się wzmocnić wewnętrznie oczekuje const MyStruct gdzieś, a tym samym nie powiedzie się z powodu następującego błędu kompilacji w MSVC7.1.

doładowania \ wiążą \ mem_fn_template.hpp (151): error C2440: 'argumentem': nie można przekonwertować z 'const MyStruct * __ W64' do 'MyStruct * const'

bym docenić każdy pomoc w poprawnym ustawieniu parametrów szablonu, więc bind rozpoznaje poprawnie parametry i pozwala na wywołanie funkcji non const.

dzięki, Carl

+0

A może zrób kopię zapasową i powiesz, co naprawdę chcesz osiągnąć?Używanie for_each z mapą z boost :: bind * może * być rozsądne, ale szanse są całkiem dobre, że inne ogólne podejście będzie działać lepiej (wielokrotnie pojawia się tego rodzaju pytanie, ponieważ 'std :: for_each' jest złym wyborem dla sytuacji, a coś takiego jak 'std :: copy' lub std :: accumulate' wykonałoby zadanie znacznie prościej). –

+0

The MyStruct jest używany w systemie cząsteczkowym, w którym MyStruct jest cząstką. Funkcja const jest funkcją draw(), funkcja non-const oblicza nową pozycję. Kluczem na mapie jest data utworzenia. W każdym razie, w punkcie, w którym napisałem pytanie, chodziło raczej o to, jak wykonać tę pracę, niż gdyby to był dobry projekt na początku. – Carl

Odpowiedz

8

IIRC, Boost.Bind wykorzystuje boost::mem_fn dla jego wiązanie z możliwością członków. Teraz, jeśli spojrzeć na mem_fun (przewiń do // data member support części), zobaczysz, że typedef jego result_type jako const &, a jednocześnie jest ma przeciążeniem operatora wywołania funkcji wspomagających wydobycie const członka z niestanowiący argumentu.

Wydaje się zatem, że problem jest to, że ten typ myli powrót mechanizmu odliczenia Boost.Bind za. Rozwiązanie powinno więc jednoznacznie powiedzieć Bind, że wynik nie jest stały:

+0

+1 Dobra robota detektywistyczna. :-) O dziwo, użycie 'boost :: lamba :: bind' będzie kompilowane bez jawnego określania typu zwracanego. Być może 'boost :: lamda :: bind' jest mądrzejszy niż' boost :: bind' w dedukowaniu typów zwracanych? –

+0

Wow, dziękuję bardzo. To kompiluje się dobrze. Chociaż uwielbiam używać funkcji Boost, wciąż trudno jest mi przeczytać większość kodu, więc nie udało mi się. Dzięki za pomoc. – Carl

+0

Myślę, że masz na myśli 'boost :: mem_fn' – Manuel

0

Problemem I nanosi: drugiego wiązania nazywany jest za nienależące funkcji. Drugi jest członkiem danych, nie sposób std :: pair

+3

Znalazłem tę technikę w tym artykule: http://www.informit.com/articles/article.aspx?p=412354&seqNum=4 Stwierdza: "Możesz powiązać ze zmienną składową, tak jak możesz, za pomocą funkcji składowej lub funkcja bezpłatna. ". Ponieważ kod for_each jest zasadniczo taki sam dla obu funkcji składowych, a problem napotykany jest tylko w wywołaniu funkcji składowej non-const, myślę, że artykuł jest poprawny. – Carl

4

Jeśli jesteś już zależy od Boost, może być skłonny do sprawdzenia Boost Foreach

BOOST_FOREACH(MyMap::value_type const& val, MyMap) 
{ 
    val.second.someConstFunction(); 
} 

Dużo dużo czytelny, choć nie wiem o problemach z wydajnością.

Należy również pamiętać, że nie można użyć matrycy wpisane w makro bez „uciekającego” przez , Charakter:

  • albo przez typedef przed
  • lub za pomocą drugiej pary nawiasów wokół typu
+0

Znam Boost Foreach i to działa oczywiście. Ale jestem po prostu ciekawy, aby znaleźć poprawną składnię powyższego rozwiązania, ponieważ powyższy kod działa dobrze dla funkcji const i kończy się niepowodzeniem dla nie const. – Carl

+4

Wierzę, że poprawny kod byłby (usuń const, jeśli chcesz zmienić wartości): BOOST_FOREACH (MyMap :: value_type const & val, theMap) {...} – Bklyn

+0

i nie musisz łączyć z boostem przy korzystaniu z Boost.Bind lub Boost.Foreach –

7

Jeśli znajdziesz się konieczności zrobić to dużo polecam użyć biblioteki Boost.RangeEx:

#include <boost/range/algorithm/for_each.hpp> 
#include <boost/range/adaptor/map.hpp> 
#include <boost/mem_fn.hpp> 
#include <map> 

struct MyStruct { 
    void someConstFunction() const; 
    void someFunction(); 
}; 

typedef std::map<int, MyStruct> MyMap; 
MyMap theMap; 

int main() 
{ 
    //call the const member function 
    boost::for_each(theMap | boost::adaptors::map_values, 
        boost::mem_fn(&MyStruct::someConstFunction)); 

    //call the non-const member function 
    boost::for_each(theMap | boost::adaptors::map_values, 
        boost::mem_fn(&MyStruct::someFunction)); 
} 

To zostało przyjęte do Boost, ale nie pochodzi z oficjalnej dystrybucji jeszcze. Do tego czasu możesz download it z Boost Vault (link do pliku zip).

+0

To wygląda na bardziej czytelne i zrozumiałe niż rozwiązanie wiążące. Na pewno warto się przyjrzeć. Dzięki za wskazówkę. – Carl

+0

@Carl - zauważ, że boost :: mem_fn jest łatwiejszy w użyciu niż boost :: bind w tym przypadku – Manuel

+0

Ta odpowiedź jest ortogonalna względem pytania, zastępuje pętlę 'std :: for_each' przez' boost :: for_each', ale nie mówi, jak użyć argumentu "boost :: bind" jako argumentu. Mimo to zapewnia obejście. –

Powiązane problemy