MSVC ++ 17 std :: copy要求“ operator-”用于自定义迭代器

时间:2019-10-16 13:03:29

标签: c++ stl c++14

我将我的项目从VC ++ 2015迁移到VC ++ 2017。 我有自己的迭代器实现。它设置了只进操作:

template <class Container>
struct NodeTableIterator
{
    typedef NodeTableIterator<Container> this_t;
    this_t& operator ++();
    this_t operator ++(int);
};

在代码中的某个地方,我将其用于std::copy

std::copy(tbl.begin(), tbl.end(),
        std::ostream_iterator<int>(std::cout, ", "));    

此行在VC ++ 2015中完全可以正常运行,但在2017年失败,原因仅在于:

  

错误C2784:'未知类型的std :: operator-(const std :: move_iterator <_RanIt>&,const std :: move_iterator <_RanIt2>&)':无法推断出'const std :: move_iterator的模板参数<_RanIt>&'from'const NodeTableIterator ...'

std::copy内部的简单检查显示了此错误来源:

    const auto _UDest = _Unchecked_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast));

_Idl_distance确实希望我的迭代器支持operator -。 您知道如何克服这种奇怪的要求吗?

2 个答案:

答案 0 :(得分:6)

您需要在类本身内提供五种类型:

template <class Container>
struct NodeTableIterator {
    using iterator_category = /* ... */;
    using value_type = /* ... */;
    using difference_type = /* ... */;
    using pointer = /* ... */;
    using reference = /* ... */;
    // ...
};

或在std::iterator_traits的自定义专业化中。否则,将无法使用标准算法中的迭代器类别上的标签分发。


参考:[iterator.traits]/1std::iterator_traits中的类型必须存在)

  

仅在迭代器方面实现算法,通常   确定对应的值和差异类型所必需   到特定的迭代器类型。因此,要求   Iterator是迭代器的类型,即类型

iterator_traits<Iterator>::difference_type
iterator_traits<Iterator>::value_type
iterator_traits<Iterator>::iterator_category
     

被定义为迭代器的差异类型,值类型和迭代器   类别。另外,类型

iterator_traits<Iterator>::reference
iterator_traits<Iterator>::pointer
     

应定义为迭代器的引用和指针类型,即   对于迭代器对象a,其类型与*a的类型相同,并且   a->。对于输出迭代器,类型

iterator_traits<Iterator>::difference_type
iterator_traits<Iterator>::value_type
iterator_traits<Iterator>::reference
iterator_traits<Iterator>::pointer
     

可以定义为void

[iterator.traits]/2std::iterator_traits中的类型可以从成员类型中生成)

  

如果Iterator具有有效的([temp.deduct])成员类型   difference_­typevalue_­typepointerreference和   iterator_­categoryiterator_­traits<Iterator>应具有   以下是可公开访问的成员:

using difference_type   = typename Iterator::difference_type;
using value_type        = typename Iterator::value_type;
using pointer           = typename Iterator::pointer;
using reference         = typename Iterator::reference;
using iterator_category = typename Iterator::iterator_category;
     

否则,iterator_­traits<Iterator>不得有任何成员   以上名称中的一个。

答案 1 :(得分:3)

您需要定义NodeTableIterator::iterator_category。更具体地说,它不能为std::random_access_iterator_tag,否则算法将要求operator-

您还需要定义

NodeTableIterator::difference_type
NodeTableIterator::value_type
NodeTableIterator::pointer
NodeTableIterator::reference

否则std::iterator_traits将没有任何这些定义。或者,您可以明确地std::iterator_traits特殊化。请注意,如果您不执行上述任何一项操作,那么NodeTableIterator根本就不是Iterator