是否有一个容器适配器可以反转迭代器的方向,所以我可以反向迭代一个容器,基于范围的for循环?
使用显式迭代器,我会将其转换为:
for (auto i = c.begin(); i != c.end(); ++i) { ...
Run Code Online (Sandbox Code Playgroud)
进入这个:
for (auto i = c.rbegin(); i != c.rend(); ++i) { ...
Run Code Online (Sandbox Code Playgroud)
我想转换这个:
for (auto& i: c) { ...
Run Code Online (Sandbox Code Playgroud)
对此:
for (auto& i: std::magic_reverse_adapter(c)) { ...
Run Code Online (Sandbox Code Playgroud)
有这样的事情还是我必须自己写?
我在C++中使用ranged有点麻烦.我正在尝试使用它来显示元素和int数组(int []),当我在main函数上执行它时,它完全正常,如:
int main(int argc, char const *argv[]) {
int v[] = {3, 4, 6, 9, 2, 1};
for (auto a : v) {
std::cout << a << " ";
}
std::cout << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我得到了我想要的和预期的输出,即:
3 4 6 9 2 1
Run Code Online (Sandbox Code Playgroud)
但是当我尝试在函数内部使用ranged时,事情变得有点奇怪,例如我遇到了这段代码的问题:
void printList(int *v);
int main(int argc, char const *argv[]) {
int v[] = {3, 4, 6, 9, 2, 1};
printList(v);
return 0;
}
void printList(int *v) {
for (auto a : v) {
std::cout << …Run Code Online (Sandbox Code Playgroud) C++ 11引入了基于范围的for循环,它使用(const)迭代器在内部实现,因此:
std::vector<std::string> vec;
for(std::string &str : vec)
{
//...
}
Run Code Online (Sandbox Code Playgroud)
基本上相当于更冗长(是的,它可以简化使用auto):
for(std::vector<std::string>::iterator it = vec.begin(); it != vec.end(); ++it)
{
//...
}
Run Code Online (Sandbox Code Playgroud)
然而,通常还需要项目的索引.第二种方法很简单:
auto index = it - vec.begin();
Run Code Online (Sandbox Code Playgroud)
在基于范围的情况下,for它不是那么简单.但我想知道这是否可行且可移植的解决方案完全避免了迭代器:
for(auto &str : vec)
{
auto index = &str - &vec[0];
}
Run Code Online (Sandbox Code Playgroud)
(const版本将是相同的,但需要注意不要将非const容器与const引用混合,这可能并不总是很明显.)
显然这取决于几个假设:
vector的迭代器只是对项目的引用(可能在标准中?)
容器保证连续(std::vector是...)
基于范围的内部实现(也可能在标准中)
在用基于范围的循环替换我的许多"旧"for循环之前,我使用visual studio 2013进行了一些测试:
std::vector<int> numbers;
for (int i = 0; i < 50; ++i) numbers.push_back(i);
int sum = 0;
//vectorization
for (auto number = numbers.begin(); number != numbers.end(); ++number) sum += *number;
//vectorization
for (auto number = numbers.begin(); number != numbers.end(); ++number) {
auto && ref = *number;
sum += ref;
}
//definition of range based for loops from http://en.cppreference.com/w/cpp/language/range-for
//vectorization
for (auto __begin = numbers.begin(),
__end = numbers.end();
__begin != __end; ++__begin) {
auto && ref = *__begin;
sum …Run Code Online (Sandbox Code Playgroud) 有许多不同的方法可以使类型/类在范围 for 循环中可用。例如,在cppreference上给出了概述:
range-expression进行评估以确定要迭代的顺序或范围。序列中的每个元素依次被取消引用,并用于使用范围声明中给定的类型和名称来初始化变量。
begin_expr并end_expr定义如下:
- 如果
range-expression是数组类型的表达式,则begin_expris__range和end_expris (__range+__bound),其中__bound是数组中元素的数量(如果数组大小未知或类型不完整,则程序格式错误)- 如果是同时具有指定成员和指定成员的
range-expression类类型的表达式(无论该成员的类型或可访问性如何),则is且isCbeginendbegin_expr__range.begin()end_expr__range.end()- 否则,
begin_exprisbegin(__range)和end_exprisend(__range),它们是通过参数相关的查找找到的(不执行非 ADL 查找)。
如果我想在函数模板中使用范围 for 循环,我想限制类型在范围 for 循环中可用,以触发编译器错误并显示一条漂亮的“约束不满足”消息。考虑以下示例:
template<typename T>
requires requires (T arg) {
// what to write here ??
}
void f(T arg) {
for ( auto e : arg ) {
} …Run Code Online (Sandbox Code Playgroud) 我编写了一个c ++函数,它汇总了一些数据,然后返回一个包含数据std::shared_ptr的新分配std::vector.类似于此的东西:
std::shared_ptr<std::vector<int>> shared_ptr_to_std_vector_of_ints()
{
auto v = std::make_shared<std::vector<int>>();
for (int i = 0; i < 3; i++) v->push_back(i);
return v;
}
Run Code Online (Sandbox Code Playgroud)
我尝试使用基于范围的for循环迭代向量的内容,但它的作用就好像向量是空的.摆弄后,我发现通过将函数返回的值赋给局部变量,然后在循环中引用它,我可以使它按照我的预期运行:
// Executes loop zero times:
std::cout << "First loop:" << std::endl;
for (int i : *shared_ptr_to_std_vector_of_ints()) std::cout << i << std::endl;
// Prints three lines, as expected
std::cout << "Second loop:" << std::endl;
auto temp = shared_ptr_to_std_vector_of_ints();
for (int i : *temp) std::cout << i << std::endl;
Run Code Online (Sandbox Code Playgroud)
剪断打印这个:
First loop:
Second loop:
1 …Run Code Online (Sandbox Code Playgroud) 因此,我决定使用mdspan普通跨度 + 元素访问函数的组合,而不是简单的组合。但是 - 我想对 mdspan 做的一件明显的事情是迭代它的元素。这就是我用一维跨度来实现的方法:
std::vector vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
auto sp = std::span(vec.data(), 12);
for (auto x : sp) {
std::cout << x << ' ';
}
std::cout << '\n';
Run Code Online (Sandbox Code Playgroud)
...但不适用于mdspan's (使用Kokkos 实现):
std::vector vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
auto ms = std::mdspan(vec.data(), 12);
for (auto x : …Run Code Online (Sandbox Code Playgroud) 在使用ranged-for循环时,我正在获取悬空引用.考虑以下C++ 14表达式(下面的完整示例程序):
for(auto& wheel: Bike().wheels_reference())
wheel.inflate();
Run Code Online (Sandbox Code Playgroud)
它的输出是:
Wheel()
Wheel()
Bike()
~Bike() with 0 inflated wheels.
~Wheel()
~Wheel()
Wheel::inflate()
Wheel::inflate()
Run Code Online (Sandbox Code Playgroud)
显然有些事情是非常错误的.车轮超出其使用寿命,结果为0,而不是预期的2.
一个简单的解决方法是为Bikein 引入一个变量main.但是,我不控制代码main或Wheel.我只能改变结构Bike.
有没有办法通过改变来修复这个例子Bike?
一个成功的解决方案解决方案要么在编译时失败,要么计算2个充气轮胎并且不会触及超出其生命周期的任何物体.
#include <cstdlib>
#include <iostream>
#include <array>
#include <algorithm>
using std::cout;
using std::endl;
struct Wheel
{
Wheel() { cout << " Wheel()" << endl; }
~Wheel() { cout << "~Wheel()" << endl; }
void inflate() { inflated = true; cout << " Wheel::inflate()" << …Run Code Online (Sandbox Code Playgroud) 我有以下代码,表示3D应用程序中的网格(为清晰起见,省略了一些代码):
class Mesh {
public:
typedef std::vector<Vertex> Vertices;
typedef std::vector<int> Elements;
template<class VerticesIt, class ElementsIt>
Mesh(const VerticesIt verticesBegin,
const VerticesIt verticesEnd,
const ElementsIt elementsBegin,
const ElementsIt elementsEnd) :
vertices_(verticesBegin, verticesEnd),
elements_(elementsBegin, elementsEnd) {
}
virtual ~Mesh();
typename Vertices::const_iterator verticesBegin() const {
return vertices_.begin();
};
typename Vertices::const_iterator verticesEnd() const {
return vertices_.end();
};
typename Elements::const_iterator elementsBegin() const {
return elements_.begin();
};
typename Elements::const_iterator elementsEnd() const {
return elements_.end();
};
private:
Vertices vertices_;
Elements elements_;
};
Run Code Online (Sandbox Code Playgroud)
它工作得非常好,为内部数据提供了清晰的界面.没有为容器公开实现细节.
我对此有一点打嗝.我不能使用基于范围的循环,必须使用迭代器:
for (auto it = …Run Code Online (Sandbox Code Playgroud) // g++ --std=c++17 test.cpp -I /usr/local/include -L /usr/local/lib -lboost_system -Wall -pedantic -Wreturn-type -Wstrict-aliasing -Wreturn-local-addr -fsanitize=address -g
// LD_LIBRARY_PATH=/usr/local/lib ./a.out
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
class A {
public:
fs::path path_;
const fs::path & path() const { return path_; }
fs::path & path() { return path_; }
};
class B {
public:
fs::path root_path_;
A path_2;
A path_3;
const fs::path & operator()() const {
for ( const auto & path : {
path_3.path(),
path_2.path(),
root_path_
}) {
if …Run Code Online (Sandbox Code Playgroud) c++ ×10
ranged-loops ×10
c++11 ×5
arrays ×1
c++-concepts ×1
c++14 ×1
c++17 ×1
c++20 ×1
c++23 ×1
fedora-25 ×1
for-loop ×1
gcc ×1
iteration ×1
iterator ×1
mdspan ×1
reference ×1
shared-ptr ×1
visual-c++ ×1