【问题标题】:Why can't I use std::get<0> in std::transform?为什么我不能在 std::transform 中使用 std::get<0>?
【发布时间】:2015-02-19 03:22:30
【问题描述】:

在尝试编译以下代码时,该代码会将 maps 密钥复制到 vector

map<string, string> mss;
vector<string> vs;

transform(mss.begin(), mss.end(), back_inserter(vs), get<0>);

VS2013 无法区分 get 的用途,但这种更简单的用法可以正常工作:

vs.push_back(get<0>(*mss.begin()));

指定get&lt;0, string, string&gt; 没有帮助。我错过了什么?

【问题讨论】:

    标签: c++ c++11 overload-resolution function-templates


    【解决方案1】:

    存储在 map 中的第一个成员是 const 限定的。所以技术上你需要

    get<0, const string, string>
    

    但这并不会将候选列表限制为一个明确的重载,因为get 至少有两个版本可用:用于 const 引用参数和用于非 const 引用参数。

    您可以使用演员表选择一个

    const string &(*g)(const pair<const string, string> &) = 
      get<0, const string, string>; 
    

    typedef map<string, string> Map;
    
    const Map::key_type &(*g)(const Map::value_type &) = 
      get<0, const Map::key_type, Map::mapped_type>; 
    

    然后做

    transform(mss.begin(), mss.end(), back_inserter(vs), g);
    

    【讨论】:

      【解决方案2】:

      std::get 有许多重载,此外,每个重载本身都是一个函数模板,因此编译器无法在您请求其中一个地址的调用站点上判断您想要哪个。如果您坚持使用std::get,则需要使用static_cast

      transform(mss.begin(), mss.end(), back_inserter(vs),
                static_cast<const map<string, string>::key_type&
                               (*)(map<string, string>::value_type&)>(std::get<0>)
                           );
      

      只要static_cast 中的类型与作为参数给出的可能函数模板的特化声明相匹配,这将起作用。此外,您不应该尝试显式指定函数模板的模板参数,如get&lt;0, string, string&gt; 等 - 这就是模板参数推导机制的用途。不仅语法丑陋,而且将来可能会添加其他重载来破坏您的编译。

      更好的选择是使用 lambda 表达式

      transform(mss.begin(), mss.end(), back_inserter(vs),
                [](map<string, string>::value_type& p){ return p.first; });
      

      通用 lambda 表达式 (C++14):

      transform(mss.begin(), mss.end(), back_inserter(vs),
                [](auto& p){ return p.first; }); // or `return std::get<0>(p);`
      

      std::mem_fn 将其参数绑定到指向数据成员或成员函数的给定指针:

      #include <functional>
      
      transform(mss.begin(), mss.end(), back_inserter(vs),
                mem_fn(&map<string, string>::value_type::first));
      

      【讨论】:

      • 谢谢。我希望能够保持超级简洁的get&lt;0&gt;,但是......它不是故意的。哦,好吧。
      猜你喜欢
      • 2016-12-05
      • 1970-01-01
      • 2012-01-17
      • 1970-01-01
      • 1970-01-01
      • 2011-01-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多