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

Why can't I use std::get<0> in std::transform?

本文关键字:std lt gt get 不能 transform 为什么      更新时间:2023-10-16

在尝试编译以下代码时,该代码会将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>没有帮助。我错过了什么?

有许多重载 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));

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

get<0, const string, string>

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

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

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);