Joh*_*mew 7 c++ algorithm containers vector c++11
如果我有一个容器std::vector<T*> items,我可以创建一个IndirectIterator包装std::vector<T*>::iterator并允许迭代T而不是T*s.
我可以专门iter_swap用于通过指针IndirectIterator制作标准算法(例如std::sort)交换项吗?
即,如果我写下以下内容,它会对标准算法产生任何影响吗?
namespace some_namespace
{
template <typename IterT>
class IndirectIterator
{
IterT m_base;
public:
typedef IterT base_iterator;
typedef /* ... */ reference;
/* ... */
reference operator*() const { **m_base; }
const base_iterator& base() const { return m_base; }
base_iterator& base() { return m_base; }
};
template <typename T>
void iter_swap(IndirectIterator<T>& a, IndirectIterator<T>& b)
{
using std::iter_swap;
iter_swap(a.base(), b.base());
}
}
Run Code Online (Sandbox Code Playgroud)
这种专业化的好处是它交换指针而不是完整的T实例,所以它更快(可能).
从 C++20 开始,答案明确“是的,您可以自定义自己的 ADL iter_swap”。STL 算法应该使用它,但不是必需的,并且在实践中存在实现差异。
要自定义自定义点,您应该使用“隐藏朋友习语”:
\nnamespace some_namespace {\n template <class IterT>\n class IndirectIterator {\n IterT m_base;\n public:\n /* ... */\n\n reference operator*() const { return **m_base; }\n const base_iterator& base() const { return m_base; }\n\n // "It\'s not a member, it\'s just a friend" \n friend void iter_swap(IndirectIterator a, IndirectIterator b) {\n using std::iter_swap;\n iter_swap(a.base(), b.base());\n }\n };\n}\nRun Code Online (Sandbox Code Playgroud)\n这里有微妙的变化:你iter_swap一直通过可变引用来获取它的参数!这是行不通的,例如,如果它传递的IndirectIterator是 const,或者是右值。迭代器参数应始终按值获取。同样,提供非常量版本的base(). 你base()是一个 getter,而不是 setter;它应该是一个 const 成员函数,因为同样的原因vector::size()是一个 const 成员函数。
最后,这里需要注意的是,您绝不能进行自定义iter_swap以执行与交换迭代器目标明显不同的任何操作。如果你这样做,那么它是未定义的行为 \xe2\x80\x94 所有的赌注都关闭 \xe2\x80\x94 程序可以做任何事情。正式地,此要求在 [ iterator.cust.swap ]中给出:
\n\n如果重载解析选择的 [
\niter_swap] 函数不交换E1和E2表示的值,则程序格式错误,无需诊断。
我相信你交换“第一级”目标而不是“第二级”目标的想法iter_swap是完全正确的,只要你永远不会依赖于观察差异。标准库仍然可以绕过,如果愿意的话iter_swap就可以;swap(*it, *kt)你的代码必须能够处理这个问题,否则“程序格式错误,不需要诊断”。(即,您必须完全相信交换这些第一级目标相当于“交换E1和E2的值”,因此可以与任何其他交换值的方法互换。您不能依赖您的使用自己的方法。)
这是 Godbolt 上的完整 C++20 示例。iter_swap截至 2023 年 2 月,我看到定制的实际使用情况如下:
| 算法 | libstdc++ 库 | 库++ | 微软 |
|---|---|---|---|
std::ranges::partition | 是的 | 是的 | 是的 |
std::ranges::sort | 不 | 不 | 是的 |
std::partition | 不 | 不 | 不 |
std::sort | 不 | 不 | 不 |