为什么我不能使用std :: get< 0>在std :: transform?

时间:2014-12-20 09:18:50

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

尝试编译以下代码,将map个密钥复制到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<0, string, string>没有帮助。我错过了什么?

2 个答案:

答案 0 :(得分:8)

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<0, string, string>等 - 这就是模板参数推导机制的用途。语法不仅难看,而且可能会在将来添加其他重载,从而破坏您的编译。

更好的选择是使用 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));

答案 1 :(得分:5)

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

get<0, const string, string>

但是这不会将候选列表限制为一个明确的重载,因为get至少有两个版本:for const reference argument和non-const reference argument。

您可以使用演员

选择一个
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);