How to apply transform to an STL map in C++

后端 未结 2 1867
陌清茗
陌清茗 2020-12-29 23:07

In C++, I\'m using transform to change all the values of a map to uppercase.

  std::map data = getData();

  // make all valu         


        
相关标签:
2条回答
  • 2020-12-29 23:35

    You are missing the const in the first type of the pair.

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

    However this is not your problem: You cannot use a map as the OutputIterator, as they do not support assignment. You can, however mutate the second argument using 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";
                  });
    

    Conceptual stuff: Calling transform with the same range as input and output is quite legit and makes a lot of sense if all your functors return by value and don't mutate their arguments. However, mutating something in place can be a faster (or at least look faster in code, nevermind the optimizing compiler) and makes a lot of sense with member functions.

    0 讨论(0)
  • 2020-12-29 23:40

    If you plan on sticking to std::transform, then you need std::inserter():

    C++03 MVCE

    typedef std::map<int, std::string> Map;
    
    struct ToUpper
    {
        Map::value_type & operator()(Map::value_type & pair) const
        {
            boost::to_upper(pair.second);
            return pair;
        }
    };
    
    int main()
    {
        Map m;
        m[0] = "snake_case";
        m[1] = "camelCase";
        m[2] = "PascalCase";
        
        std::transform(m.begin(), m.end(), std::inserter(m, m.end()), ToUpper());
        
        for (Map::const_iterator it = m.begin(); it != m.end(); ++it)
            std::cout << it->first << ", " << it->second << std::endl;
    }
    

    C++11 (you can do everything in main() really)

    int main()
    {
        auto m = getData();
    
        auto toUpper = [] (decltype(m)::value_type & pair)
        {
            boost::to_upper(pair.second);
            return pair;
        };
    
        std::transform(m.begin(), m.end(), std::inserter(m, m.end()), toUpper);
    
        for (auto const & pair : m)
            std::cout << pair.first << ", " << pair.second << std::endl;
    }
    

    C++14 (you can use auto in lambda parameters)

    int main()
    {
        auto m = getData();
    
        auto toUpper = [] (auto & pair)
        {
            boost::to_upper(pair.second);
            return pair;
        };
        std::transform(m.begin(), m.end(), std::inserter(m, m.end()), toUpper);
    
        for (auto const & pair : m)
            std::cout << pair.first << ", " << pair.second << std::endl;
    }
    

    C++17 (just because i love structured bindings)

    int main()
    {
        auto m = getData();
    
        auto toUpper = [] (auto & pair)
        {
            boost::to_upper(pair.second);
            return pair;
        };
        std::transform(m.begin(), m.end(), std::inserter(m, m.end()), toUpper);
    
        for (auto const & [key, value] : m)
            std::cout << key << ", " << value << std::endl;
    }
    
    0 讨论(0)
提交回复
热议问题