2011-10-24 15 views
15

W C++ używam transformacji, aby zmienić wszystkie wartości mapy na wielkie.Jak zastosować transformację do mapy STL w C++

std::map<std::string, std::string> data = getData(); 

    // make all values uppercase 
    std::transform(data.begin(), data.end(), data.begin(), 
     [](std::pair<std::string, std::string>& p) { 
      boost::to_upper(p.second); 
      return(p); 
     }); 

To daje mi następujący błąd kompilacji:

/opt/local/include/gcc46/c++/bits/stl_algo.h:4805:2: error: no match for call to '(main(int, char**)::<lambda(std::pair<std::basic_string<char>, std::basic_string<char> >&)>) (std::pair<const std::basic_string<char>, std::basic_string<char> >&) 

myślę, że jest coś nie tak z typem argumentu w moim wyrażenia lambda. To prawdopodobnie coś prostego, ale nie mogę się domyślić, czego się spodziewać.

+3

Zamiast zakładać, że kontener przechowuje określony typ. Możesz uzyskać dostęp do informacji o typie przez value_type. 'std :: map :: value_type' –

+0

dzięki, nadal uczę się idiomów C++ ... – daj

Odpowiedz

19

Brakuje ci const w pierwszym typie pary.

[](std::pair<const std::string, std::string>& p) { 

Nie jest to jednak problem: Nie można używać map jako OutputIterator, ponieważ nie obsługują zadania. Możesz jednak zmutować drugi argument za pomocą std::for_each.

Good old map_to_foobar:

std::for_each(data.begin(), data.end(), 
       [](std::pair<const std::string, std::string>& p) { 
       p.second = "foobar"; 
       }); 

Koncepcyjne rzeczy: Wywoływanie transform z takim samym zakresie jak jest dość legit wejście i wyjście i sprawia, że ​​wiele sensu, jeśli wszystkie funktory powrócić przez wartość i nie mutować swoje argumenty. Jednak mutowanie czegoś na miejscu może być szybsze (lub przynajmniej wyglądać szybciej w kodzie, nigdy nie myśleć o kompilatorze optymalizującym) i ma wiele sensu z funkcjami członków.

+0

Dodanie const daje mi kolejny błąd/opt/local/include/gcc46/C++/bits/stl_pair.h: 156: 2: error: przekazując 'const std :: basic_string ' jako 'ten' argument 'std :: basic_string <_CharT, _Traits, _Alloc> & std :: basic_string <_CharT, _Traits , _Alloc> :: operator = (const std :: basic_string <_CharT, _Traits, _Alloc> &) [z _CharT = char, _Traits = std :: char_traits , _Alloc = std :: allocator , std :: basic_string <_CharT , _Traits, _Alloc> = std :: basic_string ] 'kwalifikatory odrzutów [-fpermissive] – daj

+0

@daj Przepraszam, spóźniłem się. Edycja wyjaśnia to. – pmr

+2

Alternatywnie możesz użyć 'std :: transform' z iteratorem transformacji. Na przykład moje 'key_iterator', zamieszczone w [odpowiedź na inne pytanie] (http://stackoverflow.com/questions/2467000/is-there-a-java-map-keyset-equivalent-for-cs-stdmap/ 5099345 # 5099345), można w prosty sposób przekonwertować na "value_iterator". Wtedy skończyłoby się 'std :: transform (begin_values ​​(dane), end_values ​​(dane), begin_values ​​(dane), [] (std :: string s) {boost :: to_upper (s); return s;}); '. W tym przypadku proponuję 'std :: for_each', ponieważ eliminuje niepotrzebną kopię. –

Powiązane problemy