简体   繁体   English

如何使用std :: for_each或std :: transform编写此for循环?

[英]How to write this for-loop using std::for_each or std::transform?

This is more of a learning question. 这更多是一个学习问题。 Is there a way I can write the following for-loop using std::for_each or std::transform? 有没有办法我可以使用std :: for_each或std :: transform编写以下for循环? If not, is there anything in boost that can help on this? 如果没有,是否有什么可以帮助解决这一问题的? The loop simply flattens a vector of vectors into one long vector. 循环只是将向量的向量平整为一个长向量。

vector<vector<int> > int_vectors;

// ... fill int_vectors

vector<int> ints;

for (vector<vector<int> >::const_iterator iter = int_vectors.begin(); iter != int_vectors.end(); ++iter) {
   ints.insert(ints.end(), iter->begin(), iter->end());
}

I wouldn't change this to use one of the algorithms unless you have a compiler that supports lambdas. 除非您具有支持lambda的编译器,否则我不会将其更改为使用其中一种算法。 It's completely clear as written. 它写的很清楚。 Even if your compiler did support lambdas, I'd probably not change this code. 即使您的编译器确实支持lambda,我也可能不会更改此代码。

One relatively straightforward option would be to write a flattening iterator. 一个相对简单的选择是编写一个扁平化的迭代器。 I wrote one for demonstration in an answer to another question . 我写了一个示范来回答另一个问题

If you really want a one-liner and can use bind ( boost::bind from Boost, std::tr1::bind from TR1, and std::bind from C++0x will all work), then here is how that would look. 如果你真的想要一个班轮,并且可以使用bindboost::bind与Boost, std::tr1::bind从TR1和std::bind从的C ++ 0x将所有的工作),那么这里就是怎么说会看起来。 I warn you in advance: it is horrible. 我提前警告您:这太可怕了。

Edit: Technically this is also illegal. 编辑:从技术上讲这也是非法的。 The type of a Standard Library member function is unspecified, so you cannot (portably or correctly) take the address of such a member function. 标准库成员函数的类型未指定,因此您不能(便携式或正确地)获取此类成员函数的地址。 If you could correctly take the address of a Standard Library member function, this is what it would look like: 如果您可以正确获取标准库成员函数的地址,则外观如下所示:

typedef std::vector<int>::iterator (std::vector<int>::*IteratorGetter)();

std::for_each(int_vectors.begin(), int_vectors.end(),
    std::bind(
        std::bind(
            &std::vector<int>::insert<std::vector<int>::iterator>, 
            &ints, 
            std::bind((IteratorGetter)&std::vector<int>::end, &ints), 
            _1, 
            _2
        ),
        std::bind((IteratorGetter)&std::vector<int>::begin, _1),
        std::bind((IteratorGetter)&std::vector<int>::end, _1)
    )
);

(Yes, that is technically one "line of code" as it is a single statement. The only thing I have extracted is a typedef for the pointer-to-member-function type used to disambiguate the overloaded begin and end functions; you don't necessarily have to typedef this, but the code requires horizontal scrolling on Stack Overflow if I don't.) (是的,从技术上讲,这是一条“代码行”,因为它是一条语句。我提取的唯一内容是用于区分成员函数指针类型的typedef,用于消除重载的beginend函数;您不知道不一定要对此进行typedef定义,但如果不需要,则代码需要在Stack Overflow上进行水平滚动。)

If your compiler supports lambdas this is fairly simple. 如果您的编译器支持lambda,则这非常简单。 The typedefs help with readability. typedef帮助提高可读性。

typedef std::vector<int> VI;
typedef std::vector<VI> VVI;

VVI int_vectors;
VI ints;

std::for_each(int_vectors.begin(), int_vectors.end(), [&](VI &vec) {
    ints.insert(ints.end(), vec.begin(), vec.end());
});

I kno macros aren't great practice but you can do some clever things with them: 我不知道宏不是一个好习惯,但是您可以用它们做一些聪明的事情:

#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>

using namespace std;
#define all(v) (v).begin(), (v).end()
#define foreach(it, v) for(auto it = (v).begin(); it != (v).end(); ++it)

void main() {
    vector<int> vi;
    vector<vector<int>> vvi;

    foreach(it, vvi) {
        copy(all(*it), back_inserter(vi));
    }
}

You can also use std::copy and back_inserter to do what you're trying to achieve. 您还可以使用std :: copy和back_inserter来完成您要实现的目标。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM