根据对。对std :: pair <int,std :: unique_ptr <const =“” t =“”>>的向量进行排序

时间:2018-07-24 17:16:43

标签: c++ sorting smart-pointers move-semantics

我正在尝试对包含const对象的智能指针的向量对进行排序。我试图仅根据第一个对象进行排序。在下面,您可以看到(我曾多次尝试编写的代码之一)应该执行此操作的代码,以及错误的摘录。

编译器抱怨lambda参数。我试图使参数const,非const,引用,右值引用无效。请帮忙吗?

std::pair<int, std::unique_ptr<const std::string> > a;
auto uniq = std::make_unique<const std::string>("hurz");
a = std::make_pair(1,std::move(uniq));

std::pair<int, std::unique_ptr<const std::string> > b;
uniq = std::make_unique<const std::string>("hurz");
b = std::make_pair(2,std::move(uniq));

std::vector<std::pair<int,std::unique_ptr<const std::string> > > vec;

vec.push_back(std::move(a));
vec.push_back(std::move(b));

std::sort(std::make_move_iterator(vec.begin()),
    std::make_move_iterator(vec.end()),
    []
    (const std::pair<int,std::unique_ptr<const std::string> >& i1,
     const std::pair<int,std::unique_ptr<const std::string> >& i2)
    { return i1.first > i2.first;});

错误消息对我没有帮助:

error: no matching function for call to 
'swap(std::move_iterator<__gnu_cxx::__normal_iterator<std::pair<int, 
std::unique_ptr<const std::basic_string<char> > >*, std::vector<std::pair<int, 
std::unique_ptr<const std::basic_string<char> > > > > >::value_type, 
std::move_iterator<__gnu_cxx::__normal_iterator<std::pair<int, 
std::unique_ptr<const std::basic_string<char> > >*, std::vector<std::pair<int, 
std::unique_ptr<const std::basic_string<char> > > > > >::value_type)' swap(*__a, 
*__b);
candidates are:
 /usr/include/c++/4.9/bits/move.h:166:5: note: void std::swap(_Tp&, _Tp&) 
[with _Tp = std::pair<int, std::unique_ptr<const std::basic_string<char> > >]

plus many more errors in the same vein

2 个答案:

答案 0 :(得分:7)

这里的问题是使用std::make_move_iterator。当您这样做时,会将迭代器转换为move_iterator,这意味着在取消引用它们时,您将获得T&&,而不是像常规迭代器那样的T&

在实现std::swap中使用的

std::sort仅采用左值引用,因此不能绑定到已取消引用的迭代器。如果您使用

std::sort(vec.begin(),
    vec.end(),
    []
    (const std::pair<int,std::unique_ptr<const std::string> >& i1,
     const std::pair<int,std::unique_ptr<const std::string> >& i2)
    { return i1.first > i2.first;});

相反,您将拥有std::swap的左值绑定,而std::swap将适用于仅移动类型

答案 1 :(得分:0)

我在@NathanOliver的答案中添加了一些进一步的解释,这对于评论来说太长了。我猜想OP的使用思路是

std::sort(std::make_move_iterator(vec.begin()), std::make_move_iterator(vec.end()),
    [](const std::pair<int,std::unique_ptr<const std::string> >& i1,
       const std::pair<int,std::unique_ptr<const std::string> >& i2)
       { return i1.first > i2.first;});

即,将move_iterator应用于vector.begin(),是在排序例程中使用移动分配(而不是副本)。这个想法很诱人,但这不是必须的,因为在std::sort内部,分配通常是由tries to move arguments passed by referencestd::swap完成的。

另一方面,对于使用输入和输出迭代器的算法,例如最基本的std::copystd::copy_if,使用std::make_move_iterator可能会非常有用。那些通常使用*output_it = *input_it之类的结构,并且与std::make_move_iterator一起使用,对应于*output_it = std::move(*input_it),因此可以使用*output_it取消引用类型的移动分配运算符。