C++;-迭代双元组的向量 我有一个双倍的C++向量,保证有偶数个元素。该向量将一组点的坐标存储为x,y坐标:
A[2*i]是第i点的x坐标 [2*i+1]是第i点的y坐标 如何实现一个允许我使用STL风格算法的迭代器(一个采用迭代器范围的算法,其中对迭代器的解引用返回对应点的x,y坐标对应的一对双精度) 如果有帮助的话,我使用的是C++17。没有一种简单的“C++”方法可以做到干净并避免复制原始数组。总是有这样的(复制):C++;-迭代双元组的向量 我有一个双倍的C++向量,保证有偶数个元素。该向量将一组点的坐标存储为x,y坐标:,c++,vector,stl,iterator,c++17,C++,Vector,Stl,Iterator,C++17,A[2*i]是第i点的x坐标 [2*i+1]是第i点的y坐标 如何实现一个允许我使用STL风格算法的迭代器(一个采用迭代器范围的算法,其中对迭代器的解引用返回对应点的x,y坐标对应的一对双精度) 如果有帮助的话,我使用的是C++17。没有一种简单的“C++”方法可以做到干净并避免复制原始数组。总是有这样的(复制): 向量中的元素存储在连续的内存区域中,所以您可以使用简单的指针算术来访问一对双精度 迭代器的operator++应该在每次使用时跳过2倍 operator*可以将引用的元组返回到双值,
向量中的元素存储在连续的内存区域中,所以您可以使用简单的指针算术来访问一对双精度 迭代器的
operator++
应该在每次使用时跳过2倍
operator*
可以将引用的元组返回到双值,因此您可以读取(pair=*it
)或编辑值(*it=pair
)
struct Cont{
std::vector&v;
Cont(std::vector&v):v(v){}
结构迭代器:公共std::迭代器{
double*ptrData=nullptr;
迭代器(双*数据):ptrData(数据){}
迭代器和运算符++(){ptrData+=2;返回*this;}
迭代器运算符++(int){Iterator copy(*this);ptrData+=2;返回copy;}
自动运算符*(){return std::tie(*ptrData,*(ptrData+1));}
布尔运算符!=(常量迭代器和其他)常量{return ptrData!=other.ptrData;}
};
自动开始(){返回迭代器(v.data());}
自动结束(){返回迭代器(v.data()+v.size());}
};
int main(){
std::向量v;
v、 调整大小(4);
续c(v);
for(auto it=c.begin();it!=c.end();it++){
*it=std::tuple(20,30);
}
std::cout如果你能保证std::vector总是有偶数个条目,你可以利用这样一个事实,即一个双精度向量将与一个双精度向量具有相同的内存布局。这是一种肮脏的把戏,但如果你能避免的话,我不建议你这样做。好消息是,标准保证向量元素将是连续的
inline const std::vector<std::pair<double, double>>& make_dbl_pair(std::vector<double>& v)
{
return reinterpret_cast<std::vector<std::pair<double, double>>&>(v);
}
inline const std::vector和make_dbl_对(std::vector&v)
{
返回重新解释(v);
}
这只适用于使用迭代器的迭代。该大小可能是向量中对数的两倍,因为它下面仍然是一个双精度向量
例如:
int main(int argc, char* argv[])
{
std::vector<double> dbl_vec = { 0.0, 1.1, 2.2, 3.3, 4.4, 5.5 };
const std::vector<std::pair<double, double>>& pair_vec = make_dbl_pair(dbl_vec);
for (auto it = pair_vec.begin(); it != pair_vec.end(); ++it) {
std::cout << it->first << ", " << it->second << "\n";
}
std::cout << "Size: " << dbl_vec.size() << "\n";
return 0;
}
intmain(intargc,char*argv[])
{
向量dbl_vec={0.0,1.1,2.2,3.3,4.4,5};
const std::vector&pair_vec=make_dbl_pair(dbl_vec);
对于(自动it=pair_vec.begin();it!=pair_vec.end();+it){
std::cout firstC++是一个移动的目标——当涉及到迭代器时也是如此(C++20有这方面的概念…)。但是如果有一个懒惰的解决方案来解决这个问题会不会很好。例如,元组是动态生成的,而不是强制转换(参见其他答案)无需编写循环即可将向量
转换为向量
现在我觉得我需要一个免责声明,因为我不确定这是否完全正确(如果我遗漏了什么,语言律师希望会指出)。但它编译并生成预期的输出。这是什么,是吗?!是的
其思想是使用自己的迭代器构建一个伪容器(实际上只是底层容器的一个门面),动态生成所需的输出类型
#include <vector>
#include <tuple>
#include <iostream>
#include <iterator>
template <class SourceIter>
struct PairWise {
PairWise() = delete;
PairWise(SourceIter first, SourceIter last)
: first{first}
, last{last}
{
}
using value_type =
typename std::tuple<
typename SourceIter::value_type,
typename SourceIter::value_type
>;
using source_iter = SourceIter;
struct IterState {
PairWise::source_iter first;
PairWise::source_iter last;
PairWise::source_iter current;
IterState(PairWise::source_iter first, PairWise::source_iter last)
: first{first}
, last{last}
, current{first}
{
}
friend bool operator==(const IterState& a, const IterState& b) {
// std::cout << "operator==(a,b)" << std::endl;
return (a.first == b.first)
&& (a.last == b.last)
&& (a.current == b.current);
}
IterState& operator++() {
// std::cout << "operator++()" << std::endl;
if (std::distance(current,last) >= 2) {
current++;
current++;
}
return *this;
}
const PairWise::value_type operator*() const {
// std::cout << "operator*()" << std::endl;
return std::make_tuple(*current, *(current+1));
}
};
using iterator = IterState;
using const_iterator = const IterState;
const_iterator cbegin() const {
return IterState{first,last};
}
const_iterator cend() const {
auto i = IterState{first,last};
i.current = last;
return i;
}
const_iterator begin() const {
// std::cout << "begin()" << std::endl;
return IterState{first,last};
}
const_iterator end() const {
// std::cout << "end()" << std::endl;
auto i = IterState{first,last};
i.current = last;
return i;
}
source_iter first;
source_iter last;
};
std::ostream& operator<<(std::ostream& os, const std::tuple<double,double>& value) {
auto [a,b] = value;
os << "<" << a << "," << b << ">";
return os;
}
template <class Container>
auto pairwise( const Container& container)
-> PairWise<typename Container::const_iterator>
{
return PairWise(container.cbegin(), container.cend());
}
int main( int argc, const char* argv[]) {
using VecF64_t = std::vector<double>;
VecF64_t data{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
for (const auto x : pairwise(data)) {
std::cout << x << std::endl;
}
return 0;
}
#包括
#包括
#包括
#包括
模板
结构成对{
成对()=删除;
成对(先源iter,后源iter)
:first{first}
,last{last}
{
}
使用值\u类型=
typename std::tuple<
typename SourceIter::value\u type,
typename SourceIter::value\u类型
>;
使用source_iter=SourceIter;
结构IterState{
两两:源代码优先;
成对::最后一个源代码;
成对:源电流;
IterState(成对::源国际热核试验堆优先,成对::源国际热核试验堆最后)
:first{first}
,last{last}
,当前{first}
{
}
friend布尔运算符==(常量IterState&a、常量IterState&b){
//std::cout我们可以使用range-v3,带有两个适配器:
chunk(n)
获取一个范围,并将其调整为大小不重叠的范围n
transform(f)
获取x的范围
并将其调整为f(x)
把这些放在一起,我们可以创建一个适配器,它接受一个范围并产生一个非重叠对的范围:
auto-into_pairs=rv::chunk(2)
|rv::transform([](auto&&r){return std::pair(r[0],r[1]);});
使用r[0]
语法假定输入范围是随机访问的,在本例中,这是很好的,因为我们知道我们希望在向量上使用它,但也可以将其推广到仅适用于前向范围,而代价是多一些语法:
| rv::transform([](自动和&r){
自动it=范围::开始(r);
自动下一步=范围::下一步(it);
返回std::pair(*it,*next);
})
,使用fmt
方便打印:
intmain(){
向量v={1,1,2,2,3,3,4,4,5,5};
自动插入\u pairs=rv::chunk(2)
|rv::transform([](auto&&r){return std::pair(r[0],r[1]);});
//印刷品{(1,1)、(2,2)、(3,3)、(4,4)、(5,5)}
fmt::打印(“{}\n”,v|为_对);
}
问题中不清楚您想要的是pair
s还是pair
s。后者可以通过向std::pair
提供显式类型,而不是依赖于类模板参数推断来实现。我假设您正在寻找一个“懒惰的”这样,不用复制/重新格式化就可以了,对吗?正确-我假设任何人
inline const std::vector<std::pair<double, double>>& make_dbl_pair(std::vector<double>& v)
{
return reinterpret_cast<std::vector<std::pair<double, double>>&>(v);
}
int main(int argc, char* argv[])
{
std::vector<double> dbl_vec = { 0.0, 1.1, 2.2, 3.3, 4.4, 5.5 };
const std::vector<std::pair<double, double>>& pair_vec = make_dbl_pair(dbl_vec);
for (auto it = pair_vec.begin(); it != pair_vec.end(); ++it) {
std::cout << it->first << ", " << it->second << "\n";
}
std::cout << "Size: " << dbl_vec.size() << "\n";
return 0;
}
#include <vector>
#include <tuple>
#include <iostream>
#include <iterator>
template <class SourceIter>
struct PairWise {
PairWise() = delete;
PairWise(SourceIter first, SourceIter last)
: first{first}
, last{last}
{
}
using value_type =
typename std::tuple<
typename SourceIter::value_type,
typename SourceIter::value_type
>;
using source_iter = SourceIter;
struct IterState {
PairWise::source_iter first;
PairWise::source_iter last;
PairWise::source_iter current;
IterState(PairWise::source_iter first, PairWise::source_iter last)
: first{first}
, last{last}
, current{first}
{
}
friend bool operator==(const IterState& a, const IterState& b) {
// std::cout << "operator==(a,b)" << std::endl;
return (a.first == b.first)
&& (a.last == b.last)
&& (a.current == b.current);
}
IterState& operator++() {
// std::cout << "operator++()" << std::endl;
if (std::distance(current,last) >= 2) {
current++;
current++;
}
return *this;
}
const PairWise::value_type operator*() const {
// std::cout << "operator*()" << std::endl;
return std::make_tuple(*current, *(current+1));
}
};
using iterator = IterState;
using const_iterator = const IterState;
const_iterator cbegin() const {
return IterState{first,last};
}
const_iterator cend() const {
auto i = IterState{first,last};
i.current = last;
return i;
}
const_iterator begin() const {
// std::cout << "begin()" << std::endl;
return IterState{first,last};
}
const_iterator end() const {
// std::cout << "end()" << std::endl;
auto i = IterState{first,last};
i.current = last;
return i;
}
source_iter first;
source_iter last;
};
std::ostream& operator<<(std::ostream& os, const std::tuple<double,double>& value) {
auto [a,b] = value;
os << "<" << a << "," << b << ">";
return os;
}
template <class Container>
auto pairwise( const Container& container)
-> PairWise<typename Container::const_iterator>
{
return PairWise(container.cbegin(), container.cend());
}
int main( int argc, const char* argv[]) {
using VecF64_t = std::vector<double>;
VecF64_t data{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
for (const auto x : pairwise(data)) {
std::cout << x << std::endl;
}
return 0;
}