C++11,用于具有一个以上变量的每个循环
C++11 for each loop with more than one variable
我想将以下传统的for循环转换为每个循环的C++11,而不需要额外的循环构造:
int a[] = { 5, 6, 7, 8, 9, 10 };
int b[] = { 50, 60, 70, 80, 90, 100 };
// Swap a and b array elements
for (int i = 0; i < sizeof(a)/sizeof(a[0]); i++)
{
a[i] ^= b[i]; b[i] ^= a[i]; a[i] ^= b[i];
}
有没有任何方法可以在C++11中为每个循环提供一个以上的变量,比如:
for (int i, int j : ...)
没有内置的方法可以做到这一点。如果您可以使用Boost,boost::combine
将同时迭代两个(或多个)范围(Boost是否提供make_zip_range?,我如何使用Boost_FOREACH同时迭代两种向量?):
for (boost::tuple<int&, int&> ij : boost::combine(a, b)) {
int& i = boost::get<0>(ij);
int& j = boost::get<1>(ij);
// ...
}
不幸的是,访问zipped范围的元组元素中的元素非常冗长。C++17将使用结构化绑定使其可读性更强:
for (auto [&i, &j] : boost::combine(a, b)) {
// ...
}
由于您不需要脱离循环或从封闭函数返回,因此可以将boost::range::for_each
与循环的主体一起用作lambda:
boost::range::for_each(a, b, [](int& i, int& j)
{
// ...
});
然而,编写一个足够强大的for(:)
循环并不难。
首先,我们编写一个基本的范围类型:
template<class It>
struct range_t {
It b,e;
It begin() const{ return b; }
It end() const{ return e; }
range_t without_front( std::size_t count = 1 ) const {
return {std::next(begin()), end()};
}
bool empty() const { return begin()==end(); }
};
template<class It>
range_t<It> range( It b, It e ) { return {b,e}; }
template<class C>
auto range( C& c ) {
using std::begin; using std::end;
return range( begin(c), end(c) );
};
然后我们编写一个适用于范围的迭代器(比迭代器更容易):
template<class R1, class R2>
struct double_foreach_iterator {
R1 r1;
R2 r2;
void operator++() { r1 = r1.without_front(); r2 = r2.without_front(); }
bool is_end() const { return r1.empty() || r2.empty(); }
auto operator*()const {
return std::tie( *r1.begin(), *r2.begin() );
}
using self=double_foreach_iterator;
auto cur() const {
return std::make_tuple( r1.begin(), r2.begin() );
}
friend bool operator==( self const& lhs, self const& rhs ) {
if (lhs.is_end() || rhs.is_end())
return lhs.is_end() == rhs.is_end();
return lhs.cur() == rhs.cur();
}
friend bool operator!=( self const& lhs, self const& rhs ) {
return !(lhs==rhs);
}
};
现在我们进行双重迭代:
template<class A, class B>
auto zip_iterate(
A& a, B& b
) {
auto r1 = range(a);
auto r2 = range(b);
auto r1end = range(r1.end(), r1.end());
auto r2end = range(r2.end(), r2.end());
using it = double_foreach_iterator<decltype(r1), decltype(r2)>;
return range( it{r1, r2}, it{r1end, r2end} );
}
这给了我们:
for (auto tup : zip_iterate(a, b)) {
int& i = std::get<0>(tup);
int& j = std::get<1>(tup);
// ...
}
或在C++17:中
for (auto&& [i, j] : zip_iterate(a, b)) {
// ...
}
我的zip迭代不会而假设两个容器的长度相同,并将迭代到较短容器的长度。
活生生的例子。
只是为了好玩。
以下内容并不是对这个问题的严肃回答,只是一个尝试理解C++11潜力的练习(所以,请耐心等待)。
以下是一个类(类的草稿)的示例,该类接收两个大小相同的容器(使用size()
方法)(其他情况除外),以及一个自定义迭代器,该迭代器向n位元素返回std::reference_wrapper
中的std::pair
。
通过一个简单的使用示例,可以更改起始容器中的值。
不适用于旧的C样式数组,但适用于std::array
。我们讨论的是C++11,所以我想我们可以强制使用std::array
。
#include <array>
#include <vector>
#include <iostream>
#include <functional>
template <typename T1, typename T2>
class pairWrapper
{
public:
using V1 = typename std::remove_reference<decltype((T1().at(0)))>::type;
using V2 = typename std::remove_reference<decltype((T2().at(0)))>::type;
using RW1 = std::reference_wrapper<V1>;
using RW2 = std::reference_wrapper<V2>;
class it
{
public:
it (pairWrapper & pw0, std::size_t p0): pos{p0}, pw{pw0}
{ }
it & operator++ ()
{ ++pos; return *this; }
bool operator!= (const it & it0)
{ return pos != it0.pos; }
std::pair<RW1, RW2> & operator* ()
{
static std::pair<RW1, RW2>
p{std::ref(pw.t1[0]), std::ref(pw.t2[0])};
p.first = std::ref(pw.t1[pos]);
p.second = std::ref(pw.t2[pos]);
return p;
}
private:
std::size_t pos;
pairWrapper & pw;
};
it begin()
{ return it(*this, 0U); }
it end()
{ return it(*this, len); }
pairWrapper (T1 & t10, T2 & t20) : len{t10.size()}, t1{t10}, t2{t20}
{ if ( t20.size() != len ) throw std::logic_error("no same len"); }
private:
const std::size_t len;
T1 & t1;
T2 & t2;
};
template <typename T1, typename T2>
pairWrapper<T1, T2> makePairWrapper (T1 & t1, T2 & t2)
{ return pairWrapper<T1, T2>(t1, t2); }
int main()
{
std::vector<int> v1 { 1, 2, 3, 4 };
std::array<long, 4> v2 { { 11L, 22L, 33L, 44L } };
for ( auto & p : makePairWrapper(v1, v2) )
{
std::cout << '{' << p.first << ", " << p.second << '}' << std::endl;
p.first += 3;
p.second += 55;
}
for ( const auto & i : v1 )
std::cout << '[' << i << ']' << std::endl;
for ( const auto & l : v2 )
std::cout << '[' << l << ']' << std::endl;
return 0;
}
p.s.:很抱歉我的英语不好
- 在循环中按顺序遍历成员变量
- 我可以创建一个包含两个变量的 for 循环,但时间复杂度仍然为 O(n) 吗?
- 与 for 循环中的变量混淆
- 如何在循环之外重新输入变量
- 如何使用将字符串拆分为 for 循环中的变量的程序
- 在变量声明中使用 for 循环
- C++ 和 Boost.Python - 如何将变量公开给 python 并在循环中更新它?
- C++ Code 在 for 循环期间不会累积变量中的总和,仅提供最终迭代值
- C++ 在循环中添加计数器变量并再次初始化其值
- (C++)虽然循环一次不起作用,但我引入了多个变量
- 如何添加循环期间分配的变量?
- C++,每个循环初始化一个新的静态变量
- 在 for 循环中更新两个变量时遇到问题C++
- 循环中的变量被设置为下一个数组的元素始终具有相同的内存地址?
- 需要循环帮助以迭代方式添加到程序集中的总和变量
- 在 c++ 中基于范围的 for 循环中使用引用作为控制变量
- 如何在循环中动态创建变量(c++)
- 变量循环范围会导致返回局部变量的地址引用
- ifstream变量循环不打印任何内容
- c++变量/循环问题