使用常量迭代器对唯一指针的向量进行排序
Sorting a vector of unique pointers using constant iterators
我的问题是为什么我可以使用 begin/end 而不是 cbegin/cend
对唯一指针向量进行排序
这样编译:
std::sort(teachers.begin(), teachers.end(), compare_by_uniqptr);
但出于某种原因,这让我尝试引用已删除的函数的 C2280。
std::sort(teachers.cbegin(), teachers.cend(), compare_by_uniqptr);
这是一些背景信息。 'teachers' 是 Teacher 对象的唯一指针向量。
class Teacher : public Person {
private:
std::vector<std::unique_ptr<Student>> students;
public:
Teacher(std::string name) : Person(name) {}
void insert(std::string name);
int num_students() { return students.size(); }
};
std::vector<std::unique_ptr<Teacher>> teachers;
bool compare_by_uniqptr(const std::unique_ptr<Teacher>& a,
const std::unique_ptr<Teacher>& b)
{
return a.get()->num_students() > b.get()->num_students();
}
我按每个人的学生人数降序排列。 begin/end 编译但 cbegin/cend 不编译。为什么?
因为 std::sort
通过 移动 对范围内的元素进行排序。这意味着将通过迭代器修改元素;它不适用于 const
.
的迭代器
不能复制唯一指针(否则会失去唯一性)。因此,当它们被排序时,它们将需要被移动(或交换)。这些操作需要更改唯一指针的 internals。当然,您不能通过 const 引用更改对象的内部结构。
为什么 cbegin()
和 cend()
不起作用? documentation 中所述的 std::sort()
具有以下类型要求:
-RandomIt must meet the requirements of ValueSwappable and RandomAccessIterator.
-The type of dereferenced RandomIt must meet the requirements of MoveAssignable and MoveConstructible.
-Compare must meet the requirements of Compare.
重点是我的。所以 std::vector::const_iterator
不满足这些要求。因此,即使您有 std::vector<int>
并尝试使用它们也不起作用。如果你问为什么它在 begin()
/end()
和 std::unique_ptr
上工作,那么你也可以在 documentation 中看到:
std::swap(std::unique_ptr) (C++11) specializes the std::swap algorithm
(function template)
所以std::unique_ptr
因为值满足ValueSwappable概念。
这是一个解决方案。向下兼容 c++11:
#include <vector>
#include <string>
#include <memory>
#include <algorithm>
struct Person {
Person(std::string name);
};
struct Student : Person {
};
class Teacher : public Person {
private:
std::vector<std::unique_ptr<Student>> students;
public:
Teacher(std::string name) : Person(name) {}
void insert(std::string name);
int num_students() const { return students.size(); }
};
std::vector<std::unique_ptr<Teacher>> teachers;
struct by_num_students
{
bool operator()(Teacher const& l, Teacher const& r) const
{
return l.num_students() < r.num_students();
}
};
template<class Comp>
struct by_pointee_impl
{
template<class L, class R>
bool operator()(L&& l, R&& r) const
{
return comp(*l, *r);
}
Comp comp;
};
template<class Comp>
auto by_pointee(Comp comp) -> by_pointee_impl<Comp>
{
return by_pointee_impl<Comp>{comp};
};
int main()
{
std::sort(begin(teachers), end(teachers), by_pointee(by_num_students()));
}
我的问题是为什么我可以使用 begin/end 而不是 cbegin/cend
对唯一指针向量进行排序这样编译:
std::sort(teachers.begin(), teachers.end(), compare_by_uniqptr);
但出于某种原因,这让我尝试引用已删除的函数的 C2280。
std::sort(teachers.cbegin(), teachers.cend(), compare_by_uniqptr);
这是一些背景信息。 'teachers' 是 Teacher 对象的唯一指针向量。
class Teacher : public Person {
private:
std::vector<std::unique_ptr<Student>> students;
public:
Teacher(std::string name) : Person(name) {}
void insert(std::string name);
int num_students() { return students.size(); }
};
std::vector<std::unique_ptr<Teacher>> teachers;
bool compare_by_uniqptr(const std::unique_ptr<Teacher>& a,
const std::unique_ptr<Teacher>& b)
{
return a.get()->num_students() > b.get()->num_students();
}
我按每个人的学生人数降序排列。 begin/end 编译但 cbegin/cend 不编译。为什么?
因为 std::sort
通过 移动 对范围内的元素进行排序。这意味着将通过迭代器修改元素;它不适用于 const
.
不能复制唯一指针(否则会失去唯一性)。因此,当它们被排序时,它们将需要被移动(或交换)。这些操作需要更改唯一指针的 internals。当然,您不能通过 const 引用更改对象的内部结构。
为什么 cbegin()
和 cend()
不起作用? documentation 中所述的 std::sort()
具有以下类型要求:
-RandomIt must meet the requirements of ValueSwappable and RandomAccessIterator.
-The type of dereferenced RandomIt must meet the requirements of MoveAssignable and MoveConstructible.
-Compare must meet the requirements of Compare.
重点是我的。所以 std::vector::const_iterator
不满足这些要求。因此,即使您有 std::vector<int>
并尝试使用它们也不起作用。如果你问为什么它在 begin()
/end()
和 std::unique_ptr
上工作,那么你也可以在 documentation 中看到:
std::swap(std::unique_ptr) (C++11) specializes the std::swap algorithm (function template)
所以std::unique_ptr
因为值满足ValueSwappable概念。
这是一个解决方案。向下兼容 c++11:
#include <vector>
#include <string>
#include <memory>
#include <algorithm>
struct Person {
Person(std::string name);
};
struct Student : Person {
};
class Teacher : public Person {
private:
std::vector<std::unique_ptr<Student>> students;
public:
Teacher(std::string name) : Person(name) {}
void insert(std::string name);
int num_students() const { return students.size(); }
};
std::vector<std::unique_ptr<Teacher>> teachers;
struct by_num_students
{
bool operator()(Teacher const& l, Teacher const& r) const
{
return l.num_students() < r.num_students();
}
};
template<class Comp>
struct by_pointee_impl
{
template<class L, class R>
bool operator()(L&& l, R&& r) const
{
return comp(*l, *r);
}
Comp comp;
};
template<class Comp>
auto by_pointee(Comp comp) -> by_pointee_impl<Comp>
{
return by_pointee_impl<Comp>{comp};
};
int main()
{
std::sort(begin(teachers), end(teachers), by_pointee(by_num_students()));
}