带有移动迭代器的独特算法

unique algorithm with move iterators

是否允许将 std::unique 与通过 std::make_move_iterator 函数创建的迭代器一起使用?我尝试了 the following,并取得了成功:

#include <iostream>
#include <ostream>
#include <vector>
#include <algorithm>
#include <limits>
#include <iterator>

#include <cstdlib>

struct A
{

    A() : i(std::numeric_limits< double >::quiet_NaN()) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
    A(double ii) : i(ii) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
    A(A const & a) : i(a.i) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
    A(A && a) : i(std::move(a.i)) { std::cout << __PRETTY_FUNCTION__ << "\n"; a.i = std::numeric_limits< double >::quiet_NaN(); }
    A & operator = (A const & a) { std::cout << __PRETTY_FUNCTION__ << "\n"; i = a.i; return *this; }
    A & operator = (A && a) { std::cout << __PRETTY_FUNCTION__ << "\n"; i = std::move(a.i); a.i = std::numeric_limits< double >::quiet_NaN(); return *this; }
    bool operator < (A const & a) const { std::cout << __PRETTY_FUNCTION__ << "\n"; return (i < a.i); }
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
    bool operator == (A const & a) const { std::cout << __PRETTY_FUNCTION__ << "\n"; return (i == a.i); }
#pragma clang diagnostic pop

    friend
    std::ostream &
    operator << (std::ostream & o, A const & a)
    {
        return o << a.i;
    }

private :

    double i;

};

int
main()
{
    std::vector< A > v{1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 4.0, 4.0, 5.0, 6.0, 6.0, 7.0};
    std::cout << "v constructed\n\n\n\n";
    std::sort(v.begin(), v.end());
    auto const end = std::unique(std::make_move_iterator(v.begin()), std::make_move_iterator(v.end())).base();
    std::copy(v.begin(), end, std::ostream_iterator< A >(std::cout, " "));
    std::cout << std::endl;
    return EXIT_SUCCESS;
}

但也许是依赖于实现的成功?

<numeric><algorithm> 中的其他算法呢?

程序保证按标准运行。
std::unique 需要前向迭代器。显示移动迭代器满足该要求的最简单方法是检查 iterator_category typedef of move_iterator:

typedef typename iterator_traits<Iterator>::iterator_category iterator_category;

可以看到,直接适配了底层迭代器类型的迭代器类别。事实上,移动迭代器的行为几乎等同于它们的底层行为,[move.iterators]/1:

Class template move_iterator is an iterator adaptor with the same behavior as the underlying iterator except that its indirection operator implicitly converts the value returned by the underlying iterator’s indirection operator to an rvalue reference.

没有其他值得注意的要求:显然 vector<>::iterator 是一个输入迭代器(根据 [move.iter.requirements] 的要求)。 unique 本身强加的唯一相关要求是

The type of *first shall satisfy the MoveAssignable requirements (Table 22).

... 直接遇到了

请注意,使用移动迭代器不应比普通迭代器带来任何优势。在内部,重复元素是移动分配的(因此 MoveAssignable 要求),因此从 operator* 返回右值引用是多余的。