2014-12-20 3 views
8

В попытке скомпилировать следующий код, который будет скопировать map сек ключи к vector:Почему я не могу использовать std :: get <0> в std :: transform?

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> не помогло. Что мне не хватает?

ответ

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> и т. Д. - это то, что для механизма вывода аргументов шаблона. Мало того, что синтаксис уродливый, но могут быть другие перегрузки, добавленные в будущем, нарушающие вашу компиляцию.

Гораздо лучшей альтернативой является использование выражение в лямбда:

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

или родовое лямбда-выражение (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

Спасибо. Я надеялся сохранить супер-сжатие 'get <0>', но ... это не должно было быть. Ну что ж. – screwnut

5

Первый член пары, хранящейся на карте, является 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); 

 Смежные вопросы

  • Нет связанных вопросов^_^