C++ 如何为back_insert_迭代器实现end sentinel?
我想通过迭代器的consequentive值填充另一个容器的元素(现实生活中经常出现的问题),比如: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
如何实现
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> >());