如何在C++中将变换应用于STL映射

daj*_*daj 21 c++ lambda stl transform map

在C++中,我使用transform将地图的所有值更改为大写.

  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);
         });
Run Code Online (Sandbox Code Playgroud)

这给了我以下编译错误:

/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> >&)
Run Code Online (Sandbox Code Playgroud)

我认为我的lambda表达式中的参数类型有问题.它可能很简单,但我似乎无法弄清楚预期的结果.

pmr*_*pmr 23

你缺少第一种类型的const.

[](std::pair<const std::string, std::string>& p) {
Run Code Online (Sandbox Code Playgroud)

但是,这不是您的问题:您不能使用a map作为OutputIterator,因为它们不支持赋值.但是,你可以使用改变第二个参数std::for_each.

好老map_to_foobar:

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

概念性的东西:transform使用与输入和输出相同的范围调用是非常合理的,如果所有的仿函数都按值返回并且不改变它们的参数,那么这很有意义.但是,对某些内容进行变更可能会更快(或者至少在代码中看起来更快,而不是优化编译器)并且对成员函数有很大意义.

  • 或者,您可以将`std :: transform`与变换迭代器一起使用.例如,我的`key_iterator`,张贴在[另一个问题的答案]中(http://stackoverflow.com/questions/2467000/is-there-a-java-map-keyset-equivalent-for-cs-stdmap/ 5099345#5099345),可以简单地转换为`value_iterator`.然后你最终得到`std :: transform(begin_values(data),end_values(data),begin_values(data),[](std :: string s){boost :: to_upper(s); return s;} );`.在这种情况下,我建议`std :: for_each`,因为它消除了不必要的副本. (3认同)

Chn*_*sos 12

如果您打算坚持std::transform,那么您需要std::inserter()

C++03 MCVE

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;
}
Run Code Online (Sandbox Code Playgroud)

C++11(你main()真的可以做所有事情)

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;
}
Run Code Online (Sandbox Code Playgroud)

C++14(可以auto在 lambda 参数中使用)

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;
}
Run Code Online (Sandbox Code Playgroud)

C++17(只是因为我喜欢结构化绑定)

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;
}
Run Code Online (Sandbox Code Playgroud)