Можно ли использовать функцию копирования STL с картой - PullRequest
4 голосов
/ 01 июня 2011

Интересно, есть ли хитрость, чтобы использовать копирование с картами для копирования содержимого карты в массив.Поскольку карты STL представляют собой комбинацию значения ключа и сопоставленного значения, элемент карты образует пару значений ключа.Это мешает нам использовать стандартные алгоритмы, такие как std :: copy.Например, следующий код выдает ошибку:

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>

int
main()
{
  std::map <int, double> test(4);
  test[0] = 11;
  test[2] = 1.23;
  test[3] = 23.29;
  test[1] = 12.12;
  double *test_arr = (double *) malloc(4 * sizeof(double));
  std::copy(test.begin(), test.end(), test_arr);
  std::cout << test_arr[3] << std::endl;
  return 0;
}

Ошибка:

stl_copy_tests.cpp: In function ‘int main()’:
stl_copy_tests.cpp:9:32: error: no matching function for call to ‘std::map<int, double>::map(int)’
/usr/include/c++/4.5/bits/stl_map.h:170:7: note: candidates are: std::map<_Key, _Tp, _Compare, _Alloc>::map(const std::map<_Key, _Tp, _Compare, _Alloc>&) [with _Key = int, _Tp = double, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, double> >, std::map<_Key, _Tp, _Compare, _Alloc> = std::map<int, double>]
/usr/include/c++/4.5/bits/stl_map.h:159:7: note:                 std::map<_Key, _Tp, _Compare, _Alloc>::map(const _Compare&, const allocator_type&) [with _Key = int, _Tp = double, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, double> >, allocator_type = std::allocator<std::pair<const int, double> >]
/usr/include/c++/4.5/bits/stl_map.h:150:7: note:                 std::map<_Key, _Tp, _Compare, _Alloc>::map() [with _Key = int, _Tp = double, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, double> >]
In file included from /usr/include/c++/4.5/bits/char_traits.h:41:0,
                 from /usr/include/c++/4.5/ios:41,
                 from /usr/include/c++/4.5/ostream:40,
                 from /usr/include/c++/4.5/iostream:40,
                 from stl_copy_tests.cpp:1:
/usr/include/c++/4.5/bits/stl_algobase.h: In static member function ‘static _OI std::__copy_move<<anonymous>, <anonymous>, <template-parameter-1-3> >::__copy_m(_II, _II, _OI) [with _II = std::_Rb_tree_iterator<std::pair<const int, double> >, _OI = double*, bool <anonymous> = false, bool <anonymous> = false, <template-parameter-1-3> = std::bidirectional_iterator_tag]’:
/usr/include/c++/4.5/bits/stl_algobase.h:404:70:   instantiated from ‘_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false, _II = std::_Rb_tree_iterator<std::pair<const int, double> >, _OI = double*]’
/usr/include/c++/4.5/bits/stl_algobase.h:442:39:   instantiated from ‘_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false, _II = std::_Rb_tree_iterator<std::pair<const int, double> >, _OI = double*]’
/usr/include/c++/4.5/bits/stl_algobase.h:474:18:   instantiated from ‘_OI std::copy(_II, _II, _OI) [with _II = std::_Rb_tree_iterator<std::pair<const int, double> >, _OI = double*]’
stl_copy_tests.cpp:15:47:   instantiated from here
/usr/include/c++/4.5/bits/stl_algobase.h:319:6: error: cannot convert ‘std::pair<const int, double>’ to ‘double’ in assignment

Есть ли какой-нибудь простой трюк / взлом, чтобы преодолеть эту проблему.

Отказ от ответственности: Не заинтересован врешения, которые перебирают карту в цикле for и добавляют элементы в массив.

Ответы [ 5 ]

5 голосов
/ 01 июня 2011

Вы можете использовать std::transform вместо:

template <typename T, typename U>
const U &extract_second(const std::pair<T,U> &p)
{
    return p.second;
}

std::transform(test.begin(), test.end(), test_arr, extract_second<int,double>);

И как @Andre указывает в комментарии ниже, если вы хотите немного более подробных накладных расходов, вы можете избежать явного указания аргументов шаблона через функтор:

struct extract_second
{
    template <typename T, typename U>
    const U operator() (const std::pair<T,U> &p) const
    {
        return p.second;
    }
};

std::transform(test.begin(), test.end(), test_arr, extract_second());

Я уверен, что есть менее многословное решение, использующее связующие средства Boost, но я не могу вспомнить синтаксис на макушке головы.

4 голосов
/ 01 июня 2011

Фуу, маллок? В любом случае, если вы хотите скопировать карту, вы должны также запомнить ключи.

int main()
{
    std::map <int, double> test(4);
    test[0] = 11;
    test[2] = 1.23;
    test[3] = 23.29;
    test[1] = 12.12;
    std::vector<std::pair<int, double>> test_arr(test.size());
    std::copy(test.begin(), test.end(), test_arr.begin());
    std::cout << test_arr[3] << std::endl;
    return 0;
}
2 голосов
/ 01 июня 2011

Самый простой способ - использовать std::transform в сочетании с boost::bind:

typedef std::map<int, double> map_t;
map_t mm;

// add elements to mm
// ...

// copy
typedef std::vector<double> vec_t;
vec_t vv;
vv.reserve( mm.size() );
std::transform( mm.begin(), mm.end(), std::back_inserter(vv), 
  boost::bind( &map_t::value_type::second, _1 ) );

Если бы вы могли использовать C ++ 0x (безboost):

std::transform( mm.begin(), mm.end(), back_inserter(vv), 
  [](map_t::value_type val) -> double { return val.second; } );
// or
std::for_each( mm.begin(), mm.end(), 
  [&vv](map_t::value_type val) { vv.push_back( val.second ); } );
2 голосов
/ 01 июня 2011

Если вы считаете std::map контейнером STL, то это контейнер std::pair<key_type, mapped_type>. (Это то, что его value_type определено, и оно разработано так, чтобы его можно было использовать как контейнер.) Если вы хотите просто одну его часть, правильная функция std::transform, с функцией преобразования, которая отображает value_type в key_type или mapped_type. (Если вы делаете широко используется std::pair - или std::map, чей value_type является std::pair, вы, вероятно, должны иметь функциональные объекты для этого в ваш набор инструментов:

struct ExtractFirst
{
    template<typename Pair>
    typename boost::remove_const<typename Pair::first_type>::type
                        operator()( Pair const& from ) const
    {
        return from.first;
    }
};

, и то же самое для ExtractSecond.

2 голосов
/ 01 июня 2011

Ваша цель будет массив std::vector [пожалуйста!] из std::pair<int,double> объектов, если, конечно, вы сами не развернете его.

(Вы можете создать свой собственный InputIterator в качестве прокси-сервера или поиграть с std::transform и std::back_inserter, но это просто глупо. Вы сделаете свой код гораздо более многословным, чем просто циклически просматривая карту.)1013 *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...