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

scr*_*nut 8 c++ function-templates overload-resolution c++11

在尝试编译以下代码时,会将maps键复制到vector:

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

transform(mss.begin(), mss.end(), back_inserter(vs), get<0>);
Run Code Online (Sandbox Code Playgroud)

VS2013无法区分哪个get是预期的,但这个更简单的用法可以正常工作:

vs.push_back(get<0>(*mss.begin()));
Run Code Online (Sandbox Code Playgroud)

指定get<0, string, string>没有帮助.我错过了什么?

Pio*_*cki 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>)
                     );
Run Code Online (Sandbox Code Playgroud)

只要类型static_cast匹配作为参数给出的可能的函数模板的特化的声明,这将起作用.此外,您不应该尝试显式指定函数模板的模板参数get<0, string, string>等 - 这就是模板参数推导机制的用途.语法不仅难看,而且将来可能会增加其他重载,从而破坏您的编译.

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

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

一般的lambda表达式(C++ 14):

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

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

#include <functional>

transform(mss.begin(), mss.end(), back_inserter(vs),
          mem_fn(&map<string, string>::value_type::first));
Run Code Online (Sandbox Code Playgroud)


AnT*_*AnT 5

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

get<0, const string, string>
Run Code Online (Sandbox Code Playgroud)

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

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

const string &(*g)(const pair<const string, string> &) = 
  get<0, const string, string>; 
Run Code Online (Sandbox Code Playgroud)

要么

typedef map<string, string> Map;

const Map::key_type &(*g)(const Map::value_type &) = 
  get<0, const Map::key_type, Map::mapped_type>; 
Run Code Online (Sandbox Code Playgroud)

然后呢

transform(mss.begin(), mss.end(), back_inserter(vs), g);
Run Code Online (Sandbox Code Playgroud)