【问题标题】:How to write this for-loop using std::for_each or std::transform?如何使用 std::for_each 或 std::transform 编写这个 for 循环?
【发布时间】:2011-06-12 22:06:17
【问题描述】:

这更像是一个学习问题。有没有办法可以使用 std::for_each 或 std::transform 编写以下 for 循环?如果没有,是否有任何东西可以帮助解决这个问题?该循环只是将一个向量向量扁平化为一个长向量。

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());
}

【问题讨论】:

  • 我正在努力学习更多关于 STL 算法和 boost 的知识!

标签: c++ boost stl foreach transform


【解决方案1】:

除非您有支持 lambda 的编译器,否则我不会将其更改为使用其中一种算法。写的一清二楚。即使您的编译器确实支持 lambda,我也可能不会更改此代码。

一个相对简单的选择是编写一个扁平化迭代器。我在an answer to another question写了一个演示。

如果您真的想要一个单行并且可以使用bind(来自Boost 的boost::bind、来自TR1 的std::tr1::bind 和来自C++0x 的std::bind 都可以) ,那么这就是它的样子。我提前警告你:这太可怕了。

编辑:从技术上讲,这也是非法的。标准库成员函数的类型未指定,因此您不能(可移植地或正确地)获取此类成员函数的地址。如果您可以正确地获取标准库成员函数的地址,它会是这样的:

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)
    )
);

(是的,从技术上讲,这是一个“代码行”,因为它是一条语句。我提取的唯一内容是用于消除重载beginend 函数;你不一定要 typedef 这个,但如果我不这样做,代码需要在 Stack Overflow 上水平滚动。)

【讨论】:

  • 感谢 James,我确实看到了您的扁平化迭代器解决方案,但我正在寻找更直接的单行代码。不是我不喜欢上面的代码,我只是在努力学习!您提到了对 lambdas 的编译器支持。它必须得到编译器的支持还是 boost::lambda 可以工作?
  • @Haitham:我已经发布了纯单线的样子。可以说,它并不漂亮。我不知道使用 Boost.Lambda 的解决方案会是什么样子;我从来没用过。
  • C++ 是唯一一种让用户用 13 行“一行代码”替换 3 行 for 循环来折磨自己的著名语言吗? @Haitham:使用 for_each、transform 或其他几乎任何东西的场景,如果是由还不了解它们的人任意发明的,则不太可能有帮助。相反,研究其他人如何使用它们,包括如何在书籍、文章等中使用它们,并始终deliberately 评估这些用途。
  • @Fred:我喜欢用任何编程语言编写痛苦的代码 :-)。我警告过这段代码太可怕了,我强烈建议不要使用它。不过写起来很有趣。
  • @James:感谢您花时间写这篇文章,非常感谢。 @Fred:放轻松,我不会用 3 行代码替换 13 行代码。我只是好奇怎么能做到这样的事情!谢谢大家!
【解决方案2】:

如果您的编译器支持 lambda,这相当简单。 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());
});

【讨论】:

  • 很遗憾,我的编译器不支持 lambda。这是 gcc 3.4.6 ......很老了!不过代码不错!
【解决方案3】:

我知道宏不是很好的做法,但你可以用它们做一些聪明的事情:

#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));
    }
}

您还可以使用 std::copy 和 back_inserter 来完成您想要实现的目标。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-20
    • 2012-08-10
    • 2012-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多