2011-06-01 86 views
4

我想知道是否有任何技巧使用地图复制功能将地图内容复制到数组中。由于STL地图由键值和映射值组合,因此地图的元素形成键值对。这阻止了我们使用标准算法,如std :: copy。例如下面的代码提供了错误:是否可以使用地图的STL复制功能

#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循环中迭代映射的解决方案不感兴趣,并向元素添加元素。除非,是的,你自己把它打开

+0

在您免责声明:你到底是什么做你认为'std :: copy'呢? – Xeo 2011-06-01 11:10:42

+1

@Xeo:他意味着他不想在他的代码中写出循环。 – 2011-06-01 11:11:49

+0

重度相关:http://stackoverflow.com/questions/771453/copy-map-values-to-vector-in-stl – 2011-06-01 11:12:41

回答

5

你可以使用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粘合剂的较不详细的解决方案,但我记不起头顶的语法。

+2

我喜欢写'extract_second'为:'struct extract_second {template const U&operator()(const std :: pair &p){return p.second;} const};'你可以省略调用中的模板参数:'std :: transform(test.begin(),test.end(),test_arr,extract_second());' – 2011-06-01 11:28:42

+0

@Andre:谢谢!我已将您的版本集成到我的答案中。 – 2011-06-01 11:38:50

+0

感谢奥利,我忘了使用std :: transform,同时詹姆斯指出了从地图中提取值的提升方式。 – systemsfault 2011-06-01 11:50:00

2

你的目标将是一个 阵列 std::vector[请!] std::pair<int,double>对象

(你可以创建自己的InputIterator作为代理,或与std::transformstd::back_inserter玩,但只是不懂事,你会让你的代码远比仅仅通过地图循环更详细。)

+1

或者,如果你想要一个双打数组并且不想写一个循环,你可以而是写一个输出迭代器,用'operator =(const pair &p){*(this-> underlying_ptr)= p.second; }'。 Boost迭代器助手可能会有这样做,我没有看过。 – 2011-06-01 11:12:48

+0

@Steve:是的,你可以像'InputIterator'一样容易地将逻辑应用于'OutputIterator'。可能更容易,现在你提到它。 – 2011-06-01 11:13:36

4

Ewww,malloc?无论如何,如果你想复制地图,你也必须记住钥匙。

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

如果你考虑std::map STL容器,那么它的 std::pair<key_type, mapped_type>的容器。 (这是它的value_type被定义为 ,它被设计成它可以用作容器的一个 )。如果你只需要它的一部分,正确的功能是 std::transform,带有一个转换函数映射 value_typekey_typemapped_type。 (如果您 多大用处的std::pair —或std::map,其value_typestd::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

最简单的方法是结合使用std::transformboost::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); }); 
相关问题