Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何为back_insert_迭代器实现end sentinel?_C++_Algorithm_Stl_Iterator_Idioms - Fatal编程技术网

C++ 如何为back_insert_迭代器实现end sentinel?

C++ 如何为back_insert_迭代器实现end sentinel?,c++,algorithm,stl,iterator,idioms,C++,Algorithm,Stl,Iterator,Idioms,我想通过迭代器的consequentive值填充另一个容器的元素(现实生活中经常出现的问题),比如: 如何实现EndSentinel和操作符!=(ForwardIterator,EndSentinel)要使上述物联网在物联网(std::back\u inserter(c1),something(c1,c1.size()),std::begin(c1))中的循环的步骤完全停止(c1.size()我想你做不到,或者我不明白你的问题,但是 根据,该算法适用于现有的元素范围,因此将其与:std::bac

我想通过迭代器的consequentive值填充另一个容器的元素(现实生活中经常出现的问题),比如:


如何实现
EndSentinel
操作符!=(ForwardIterator,EndSentinel)
要使上述
物联网
物联网(std::back\u inserter(c1),something(c1,c1.size()),std::begin(c1))
中的
循环的
步骤完全停止(
c1.size()
我想你做不到,或者我不明白你的问题,但是

根据,该算法适用于现有的元素范围,因此将其与:
std::back\u inserter
作为基本用于插入元素的第一个迭代器一起使用是没有意义的

我想通过迭代器的consequentive值填充一个容器到另一个容器的元素

使用
生成的不同解决方案:

std::vector src={0,1,2,3};
std::向量dst;
std::generate_n(std::back_inserter(dst),src.size(),[it=src.begin()]()可变{returnit++;});

我认为你做不到——或者我不理解你的问题,但是

根据,该算法适用于现有的元素范围,因此将其与:
std::back\u inserter
作为基本用于插入元素的第一个迭代器一起使用是没有意义的

我想通过迭代器的consequentive值填充一个容器到另一个容器的元素

使用
生成的不同解决方案:

std::vector src={0,1,2,3};
std::向量dst;
std::generate_n(std::back_inserter(dst),src.size(),[it=src.begin()]()可变{returnit++;});

您的问题包括一个
物联网
实现,它与我认为的标准中的实现不同。这是我知道的标准版本

您的
iota
(在我的代码中将其重命名为
miota
)允许不同类型的迭代器用于开始和结束

你在算法中想要的是;在处理所有值之前,end sentinel需要与begin(插入器)不同。对于处理值,您仅获取一个对象,并在该对象上使用增量和复制构造

因此,您的end sentinel应该知道值处理,并且当完成时,end sentinel应该以某种方式与插入器相等

我是通过在名为
IotaHelper
的类中保存原始容器的开始/结束迭代器来实现的。这使用
shared\u ptr
与sentinel类共享状态,该类称为
IotaEndSentinel

当您在
miota
内部增加
值时,实际上会增加
IotaHelper
的开始迭代器。当您使用插入器和sentinel检查相等性时,它实际上会检查
IotaHelper
中的迭代器相等性

所有带有基本示例的代码如下所示:

#include <iterator>
#include <numeric>
#include <vector>
#include <iostream>
#include <utility>
#include <memory>

template< typename ForwardIterator, typename EndSentinel, typename T >
void miota(ForwardIterator first, EndSentinel last, T value)
{
    for (; first != last; ++first) {
        *first = value;
        ++value;
    }
}

template<typename Container>
struct IotaHelper
{
    using Iterator = typename Container::iterator;
    using IteratorPair = std::pair<Iterator, Iterator>;

    IotaHelper(Iterator begin, Iterator end)
        :
        pair(std::make_shared<IteratorPair>(begin, end))
    { }

    operator Iterator()
    {
        return pair->first;
    }

    IotaHelper& operator++()
    {
        ++pair->first;
        return *this;
    }

    std::shared_ptr<IteratorPair> pair;
};

template<typename Container>
struct IotaEndSentinel
{
    using Helper = IotaHelper<Container>;
    using Iterator = typename Helper::Iterator;

    IotaEndSentinel(const Helper& helper)
        :
        helper(helper)
    {}

    template<typename C>
    friend bool operator!=(const std::back_insert_iterator<C>& bii,
                           const IotaEndSentinel& sentinel)
    {
        return sentinel.helper.pair->first != sentinel.helper.pair->second;
    }

    Helper helper;
};

int main()
{
    using Container0 = std::vector<int>;
    using Container1 = std::vector<Container0::iterator>;

    Container0 c0 = {1, 2, 3, 4, 5};
    Container1 c1;

    IotaHelper<Container0> iotaHelper(c0.begin(), c0.end());

    miota(std::back_inserter(c1),
          IotaEndSentinel<Container0>(iotaHelper), 
          iotaHelper);

    std::cout << "Result: ";
    for (auto iter : c1)
    {
        std::cout << *iter << ", ";
    }

    std::cout << std::endl;
}
#include <iterator>
#include <numeric>
#include <vector>
#include <iostream>
#include <utility>
#include <memory>

template< typename ForwardIterator, typename EndSentinel, typename T >
void miota(ForwardIterator first, EndSentinel last, T value)
{
    for (; first != last; ++first) {
        *first = value;
        ++value;
    }
}

template<typename InsertIterator, typename Iterator>
struct InsertWrapper
{
    InsertWrapper(const InsertIterator& inserter, const Iterator& iter)
        :
        inserter(inserter),
        iter(iter)
    { }

    bool operator!=(const InsertWrapper& other) const
    {
        //only compare process iterators
        return iter != other.iter;
    }

    bool operator!=(const Iterator& sentinel) const
    {
        //compare process iterator against the sentinel
        return iter != sentinel;
    }

    InsertIterator& operator*()
    {
        //return inserter for dereference
        return inserter;
    }

    InsertWrapper& operator++()
    {
        //iterate inserter as the process progresses
        ++inserter;
        ++iter;

        return *this;
    }

    InsertIterator inserter;
    Iterator iter;
};

template<typename InsertIterator, typename Iterator>
InsertWrapper<InsertIterator, Iterator> WrapInserter(const InsertIterator& inserter,
                                                     const Iterator& iter)
{
    return InsertWrapper<InsertIterator, Iterator>(inserter, iter);
}

int main()
{
    using Container0 = std::vector<int>;
    using Container1 = std::vector<Container0::iterator>;

    Container0 c0 = {1, 2, 3, 4, 5};
    Container1 c1;

    //use wrapper as usual iterator begin/end
    std::iota(WrapInserter(std::back_inserter(c1), c0.begin()),
              WrapInserter(std::back_inserter(c1), c0.end()), 
              c0.begin());

    std::cout << "std::iota result: ";
    for (auto iter : c1)
    {
        std::cout << *iter << ", ";
    }

    std::cout << std::endl;

    c1.clear();

    miota(WrapInserter(std::back_inserter(c1), c0.begin()),
          c0.end(), //end iterator as sentinel
          c0.begin());

    std::cout << "miota result: ";
    for (auto iter : c1)
    {
        std::cout << *iter << ", ";
    }

    std::cout << std::endl;
}
编辑:

在使用堆分配之后,我感觉到了代码的味道。我们可以对“迭代器和过程”进行推理,而不是试图对“值和过程”进行推理

我们可以构建一个迭代器包装器,它同时包含进程迭代器和插入迭代器

当算法需要取消对包装器的引用时,它将返回插入迭代器

当算法需要与其他“wrapper或sentinel”进行比较时,wrapper将比较进程迭代器

最后,我们可以将这种迭代器用于
std::iota
和您的
miota

完整示例如下:

#include <iterator>
#include <numeric>
#include <vector>
#include <iostream>
#include <utility>
#include <memory>

template< typename ForwardIterator, typename EndSentinel, typename T >
void miota(ForwardIterator first, EndSentinel last, T value)
{
    for (; first != last; ++first) {
        *first = value;
        ++value;
    }
}

template<typename Container>
struct IotaHelper
{
    using Iterator = typename Container::iterator;
    using IteratorPair = std::pair<Iterator, Iterator>;

    IotaHelper(Iterator begin, Iterator end)
        :
        pair(std::make_shared<IteratorPair>(begin, end))
    { }

    operator Iterator()
    {
        return pair->first;
    }

    IotaHelper& operator++()
    {
        ++pair->first;
        return *this;
    }

    std::shared_ptr<IteratorPair> pair;
};

template<typename Container>
struct IotaEndSentinel
{
    using Helper = IotaHelper<Container>;
    using Iterator = typename Helper::Iterator;

    IotaEndSentinel(const Helper& helper)
        :
        helper(helper)
    {}

    template<typename C>
    friend bool operator!=(const std::back_insert_iterator<C>& bii,
                           const IotaEndSentinel& sentinel)
    {
        return sentinel.helper.pair->first != sentinel.helper.pair->second;
    }

    Helper helper;
};

int main()
{
    using Container0 = std::vector<int>;
    using Container1 = std::vector<Container0::iterator>;

    Container0 c0 = {1, 2, 3, 4, 5};
    Container1 c1;

    IotaHelper<Container0> iotaHelper(c0.begin(), c0.end());

    miota(std::back_inserter(c1),
          IotaEndSentinel<Container0>(iotaHelper), 
          iotaHelper);

    std::cout << "Result: ";
    for (auto iter : c1)
    {
        std::cout << *iter << ", ";
    }

    std::cout << std::endl;
}
#include <iterator>
#include <numeric>
#include <vector>
#include <iostream>
#include <utility>
#include <memory>

template< typename ForwardIterator, typename EndSentinel, typename T >
void miota(ForwardIterator first, EndSentinel last, T value)
{
    for (; first != last; ++first) {
        *first = value;
        ++value;
    }
}

template<typename InsertIterator, typename Iterator>
struct InsertWrapper
{
    InsertWrapper(const InsertIterator& inserter, const Iterator& iter)
        :
        inserter(inserter),
        iter(iter)
    { }

    bool operator!=(const InsertWrapper& other) const
    {
        //only compare process iterators
        return iter != other.iter;
    }

    bool operator!=(const Iterator& sentinel) const
    {
        //compare process iterator against the sentinel
        return iter != sentinel;
    }

    InsertIterator& operator*()
    {
        //return inserter for dereference
        return inserter;
    }

    InsertWrapper& operator++()
    {
        //iterate inserter as the process progresses
        ++inserter;
        ++iter;

        return *this;
    }

    InsertIterator inserter;
    Iterator iter;
};

template<typename InsertIterator, typename Iterator>
InsertWrapper<InsertIterator, Iterator> WrapInserter(const InsertIterator& inserter,
                                                     const Iterator& iter)
{
    return InsertWrapper<InsertIterator, Iterator>(inserter, iter);
}

int main()
{
    using Container0 = std::vector<int>;
    using Container1 = std::vector<Container0::iterator>;

    Container0 c0 = {1, 2, 3, 4, 5};
    Container1 c1;

    //use wrapper as usual iterator begin/end
    std::iota(WrapInserter(std::back_inserter(c1), c0.begin()),
              WrapInserter(std::back_inserter(c1), c0.end()), 
              c0.begin());

    std::cout << "std::iota result: ";
    for (auto iter : c1)
    {
        std::cout << *iter << ", ";
    }

    std::cout << std::endl;

    c1.clear();

    miota(WrapInserter(std::back_inserter(c1), c0.begin()),
          c0.end(), //end iterator as sentinel
          c0.begin());

    std::cout << "miota result: ";
    for (auto iter : c1)
    {
        std::cout << *iter << ", ";
    }

    std::cout << std::endl;
}
#包括
#包括
#包括
#包括
#包括
#包括
模板
void miota(首先是前向迭代器,最后是EndSentinel,T值)
{
for(;first!=last;++first){
*第一个=值;
++价值观;
}
}
模板
结构插入包装器
{
InsertWrapper(常量插入器和插入器、常量迭代器和iter)
:
插入器(插入器),
国际热核实验堆(iter)
{ }
布尔运算符!=(常量插入包装器和其他)常量
{
//仅比较进程迭代器
return iter!=other.iter;
}
布尔运算符!=(常量迭代器和哨兵)常量
{
//将进程迭代器与sentinel进行比较
返回iter!=哨兵;
}
插入器和运算符*()
{
//用于取消引用的返回插入器
回位插入器;
}
InsertWrapper&运算符++()
{
//随着过程的进行,迭代插入器
++插入器;
++iter;
归还*这个;
}
插入器插入器;
迭代器iter;
};
模板
InsertWrapper WrapInserter(常量插入器和插入器,
常量迭代器(iter)
{
返回InsertWrapper(inserter,iter);
}
int main()
{
使用Container0=std::vector;
使用Container1=std::vector;
container0c0={1,2,3,4,5};
集装箱1 c1;
//像往常一样使用包装器迭代器begin/end
std::iota(WrapInserter(std::back_inserter(c1),c0.begin()),
WrapInserter(std::back_inserter(c1),c0.end()),
c0.begin());

std::cout您的问题包括一个
iota
实现,它与我认为的标准中的实现不同。这是我知道的标准版本

您的
iota
(在我的代码中将其重命名为
miota
)允许不同类型的迭代器用于开始和结束

在算法中您需要的是:在处理所有值之前,end sentinel需要与begin(插入器)不同。对于处理值,您只获取一个对象,并在该对象上使用增量和复制构造

因此,您的end sentinel应该知道值处理,完成后end sentinel应该变得相等
template<typename SourceContainer, typename IteratorContainer>
void FillIterators(SourceContainer& sc, IteratorContainer& ic)
{
    for (auto iter = sc.begin(); iter != sc.end(); ++iter)
    {
        ic.insert(ic.end(), iter);
    }
}
#include <iterator>
#include <numeric>
#include <vector>
#include <iostream>
#include <utility>
#include <memory>

template< typename ForwardIterator, typename EndSentinel, typename T >
void miota(ForwardIterator first, EndSentinel last, T value)
{
    for (; first != last; ++first) {
        *first = value;
        ++value;
    }
}

template<typename InsertIterator, typename Iterator>
struct InsertWrapper
{
    InsertWrapper(const InsertIterator& inserter, const Iterator& iter)
        :
        inserter(inserter),
        iter(iter)
    { }

    bool operator!=(const InsertWrapper& other) const
    {
        //only compare process iterators
        return iter != other.iter;
    }

    bool operator!=(const Iterator& sentinel) const
    {
        //compare process iterator against the sentinel
        return iter != sentinel;
    }

    InsertIterator& operator*()
    {
        //return inserter for dereference
        return inserter;
    }

    InsertWrapper& operator++()
    {
        //iterate inserter as the process progresses
        ++inserter;
        ++iter;

        return *this;
    }

    InsertIterator inserter;
    Iterator iter;
};

template<typename InsertIterator, typename Iterator>
InsertWrapper<InsertIterator, Iterator> WrapInserter(const InsertIterator& inserter,
                                                     const Iterator& iter)
{
    return InsertWrapper<InsertIterator, Iterator>(inserter, iter);
}

int main()
{
    using Container0 = std::vector<int>;
    using Container1 = std::vector<Container0::iterator>;

    Container0 c0 = {1, 2, 3, 4, 5};
    Container1 c1;

    //use wrapper as usual iterator begin/end
    std::iota(WrapInserter(std::back_inserter(c1), c0.begin()),
              WrapInserter(std::back_inserter(c1), c0.end()), 
              c0.begin());

    std::cout << "std::iota result: ";
    for (auto iter : c1)
    {
        std::cout << *iter << ", ";
    }

    std::cout << std::endl;

    c1.clear();

    miota(WrapInserter(std::back_inserter(c1), c0.begin()),
          c0.end(), //end iterator as sentinel
          c0.begin());

    std::cout << "miota result: ";
    for (auto iter : c1)
    {
        std::cout << *iter << ", ";
    }

    std::cout << std::endl;
}
template<typename InIter, typename InSentinel, typename OutIter, typename OutSentinel>
OutIter modernAlgorithm(InIter first, InSentinel last, OutIter outFirst, OutSentinel outLast);
template<typename T>
struct TrivialSentinel
{
    bool operator==(const T&) { return false; }
    bool operator!=(const T&) { return true; }
    friend bool operator==(const T&, TrivialSentinel&) { return false; }
    friend bool operator!=(const T&, TrivialSentinel&) { return true; }
};

modernAlgorithm(v.begin(), v.end(), std::back_inserter(r), TrivialSentinel<decltype(std::back_inserter(r))>());
template<typename InIter, typename OutIter>
OutIter olderAlgorithm(InIter first, InIter last, OutIter outFirst, OutIter outLast);
// C++20

template<typename C>
struct BackInsertIteratorWithSentinel : public std::back_insert_iterator<C>
{
    BackInsertIteratorWithSentinel() {}  // C++20 only
    BackInsertIteratorWithSentinel(C& c) : std::back_insert_iterator<C>(c) {}
    
    bool operator==(const BackInsertIteratorWithSentinel&) { return false; }
    bool operator!=(const BackInsertIteratorWithSentinel&) { return true; }
};

template<typename C>
BackInsertIteratorWithSentinel<C> BackInserterWithSentinel(C& c)
{
    return BackInsertIteratorWithSentinel<C>(c);
}

template<typename C>
BackInsertIteratorWithSentinel<C> BackInserterWithSentinel()
{
    return BackInsertIteratorWithSentinel<C>();
}

olderAlgorithm(v.begin(), v.end(), BackInserterWithSentinel(r), BackInserterWithSentinel<std::vector<int> >());