为什么我不能使用std::在std中得到::转换?

时间:2021-07-25 18:55:36

In trying to compile the following code which would copy a maps keys to a vector:

在尝试编译下列代码时,将复制一个映射键到一个向量:

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

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

VS2013 can't distinguish which get is intended but this simpler usage works just fine:

VS2013不能区分哪个是故意的,但是这个简单的用法很好:

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

Specifying get<0, string, string> didn't help. What am I missing?

指定get<0, string, string>没有帮助。我缺少什么?

2 个解决方案

#1


8  

There are many overloads of std::get, where, in addition, each is a function template itself, therefore the compiler can't tell which one you want at the call site where you request for the address of one of them. If you insist on using std::get, you'd need to use static_cast:

还有很多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>)
                     );

Which will work as long as the type in static_cast matches the declaration of a possible function template's specialization given as the argument. Also, you shoudn't try to explicitly specify the template arguments of function templates like get<0, string, string> etc. - this is what the template argument deduction mechanism is for. Not only is the syntax ugly, but there can be other overloads added in the future breaking your compilation.

只要static_cast中的类型与可能的函数模板的专门化声明相匹配,就可以工作。另外,您不应该尝试显式地指定函数模板的模板参数,比如get<0, string, string>等等,这是模板参数推导机制的目的。不仅语法很难看,而且将来还会添加其他的重载,从而破坏编译。

A much better alternative is to use a lambda expression:

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

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

or a generic lambda expression (C++14):

或一个通用的lambda表达式(c++ 14):

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

or std::mem_fn which binds its argument to a given pointer to a data member or a member function:

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

#include <functional>

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

#2


5  

The first member of the pair stored in map is const-qualified. So technically you need

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

get<0, const string, string>

But that does not limit the list of candidates to one unambiguous overload, since get is available in at least two versions: for const reference argument and for non-const reference argument.

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

You can choose one by using a cast

你可以选择一个演员。

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

or

typedef map<string, string> Map;

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

and then do

然后做

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

#1


8  

There are many overloads of std::get, where, in addition, each is a function template itself, therefore the compiler can't tell which one you want at the call site where you request for the address of one of them. If you insist on using std::get, you'd need to use static_cast:

还有很多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>)
                     );

Which will work as long as the type in static_cast matches the declaration of a possible function template's specialization given as the argument. Also, you shoudn't try to explicitly specify the template arguments of function templates like get<0, string, string> etc. - this is what the template argument deduction mechanism is for. Not only is the syntax ugly, but there can be other overloads added in the future breaking your compilation.

只要static_cast中的类型与可能的函数模板的专门化声明相匹配,就可以工作。另外,您不应该尝试显式地指定函数模板的模板参数,比如get<0, string, string>等等,这是模板参数推导机制的目的。不仅语法很难看,而且将来还会添加其他的重载,从而破坏编译。

A much better alternative is to use a lambda expression:

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

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

or a generic lambda expression (C++14):

或一个通用的lambda表达式(c++ 14):

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

or std::mem_fn which binds its argument to a given pointer to a data member or a member function:

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

#include <functional>

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

#2


5  

The first member of the pair stored in map is const-qualified. So technically you need

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

get<0, const string, string>

But that does not limit the list of candidates to one unambiguous overload, since get is available in at least two versions: for const reference argument and for non-const reference argument.

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

You can choose one by using a cast

你可以选择一个演员。

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

or

typedef map<string, string> Map;

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

and then do

然后做

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