iter_swap可以专门吗?

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实例,所以它更快(可能).

Quu*_*one 1

从 C++20 开始,答案明确“是的,您可以自定义自己的 ADL iter_swap”。STL 算法应该使用它,但不是必需的,并且在实践中存在实现差异。

\n

要自定义自定义点,您应该使用“隐藏朋友习语”:

\n
namespace 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}\n
Run Code Online (Sandbox Code Playgroud)\n

这里有微妙的变化:你iter_swap一直通过可变引用来获取它的参数!这是行不通的,例如,如果它传递的IndirectIterator是 const,或者是右值。迭代器参数应始终按值获取。同样,提供非常量版本的base(). 你base()是一个 getter,而不是 setter;它应该是一个 const 成员函数,因为同样的原因vector::size()是一个 const 成员函数。

\n

最后,这里需要注意的是,您绝不能进行自定义iter_swap以执行与交换迭代器目标明显不同的任何操作。如果你这样做,那么它是未定义的行为 \xe2\x80\x94 所有的赌注都关闭 \xe2\x80\x94 程序可以做任何事情。正式地,此要求在 [ iterator.cust.swap ]中给出:

\n
\n

如果重载解析选择的 [ iter_swap] 函数不交换E1E2表示的值,则程序格式错误,无需诊断。

\n
\n

我相信你交换“第一级”目标而不是“第二级”目标的想法iter_swap是完全正确的,只要你永远不会依赖于观察差异。标准库仍然可以绕过,如果愿意的话iter_swap就可以;swap(*it, *kt)你的代码必须能够处理这个问题,否则“程序格式错误,不需要诊断”。(即,您必须完全相信交换这些第一级目标相当于“交换E1E2的值”,因此可以与任何其他交换值的方法互换。您不能依赖您的使用自己的方法。)

\n

这是 Godbolt 上的完整 C++20 示例。iter_swap截至 2023 年 2 月,我看到定制的实际使用情况如下:

\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n
算法libstdc++ 库库++微软
std::ranges::partition是的是的是的
std::ranges::sort是的
std::partition
std::sort
\n