C++重复N次迭代

8

我可以清楚地做到这样:

for(int i = 0; i < 10000; i++)
    testIteration();

但是是否有类似的一行代码的标准函数?像这样:

std::repeat(10000, testIteration);

3
在C++11中没有相应的功能。可能可以使用C++20的rangesstd::for_each完成一些操作。在C++20变得广泛可用之前,你可以使用ranges库,这是C++20 ranges的基础库。 - Some programmer dude
7
如果你正在使用循环来对容器的每个元素执行某些操作,那么有标准算法可用。但是,如果要重复调用函数任意次数......这就是循环结构的用途,而标准库很少尝试复制可以更轻松地使用语言特性完成的内容。如果你真的需要这样的功能,请自己编写它 - 只是不要尝试将其放入命名空间std中(因为这样做会导致未定义的行为)。 - Peter
1
新的std::for_each和新的for语法都是为了帮助减少经常需要的样板代码。然而,在这种情况下,通常实际上会导致更多的样板代码。考虑到你想调用的函数是一个类的成员函数的情况;你不能简单地像在这里一样传递函数指针。 - UKMonkey
3
这是一个情况,在我的看法中,你很难在可读性方面超越那个循环。 - StoryTeller - Unslander Monica
好的,1/你应该真正使用循环来完成这个任务;2/有std::for_each_n,但它在gcc和clang中没有实现;3/C++20范围可能是一个解决方案;4/提醒一下1/。 - YSC
显示剩余2条评论
6个回答

11
C++20提议标准中,有一个关于iota_view的示例:
for (int i : iota_view{1, 10})
  cout << i << ' '; // prints: 1 2 3 4 5 6 7 8 9

但目前,可以使用range-v3库:

for (int _ : view::iota{0, 10})
    testIteration();            // calls testIteration 10 times.

4

但是是否有标准函数可以在一行中执行类似的操作呢?

不,标准库中没有算法可以做到这一点(至少没有不需要编写无用样板代码的算法)。正如其他人已经提到的,循环是最可读且最不混淆的方式来执行 n 次“某事”。

话虽如此,如果你把它看作是一个练习,想要更简洁的语法,你可以写出这样的代码:

#include <iostream>
struct my_counter {    
    int stop;
    struct iterator {
        int count;    
        iterator& operator++() { ++count; return *this; }
        int operator*() { return count;}
        bool operator!=(const iterator& other) { return count != other.count; }
    };
    iterator begin() { return {0}; }
    iterator end() { return {stop};}    
};

void print() { std::cout << "x"; }

int main() {
     for (auto x : my_counter{5}) print();
}

然而,我强烈建议不要使用类似的东西。每个人都知道循环的工作原理和它所做的事情。习惯于for循环,您可以在眨眼之间阅读for循环,而其他任何东西都是不寻常的、令人惊讶的和难以理解的,除非有一个标准算法(尽管我怀疑这种特殊情况的算法会有很大用处)。当你可以使用循环时,为什么要重新发明轮子呢?


你明确地问道:“为什么要重新造轮子,而不是使用循环?”我回答了你。 - David H Parry
1
@DavidHParry,这怎么算是一个答案呢?这跟什么都没讲一样。为什么?意大利面!: P。说真的,我不明白其中一个在并行方面比另一个更好。 - 463035818_is_not_a_number
去看看C++中std::execution::*和STD库之间的关系。不用谢。 - David H Parry
@DavidHParry 没有标准算法可以满足操作者的需求,因此我不明白标准算法如何具有执行策略来决定使用for循环还是非并行手写算法,两者都可以同样好/坏地并行化。 - 463035818_is_not_a_number
@DavidHParry,OP的示例中没有并行性,但是有一个明显具有副作用的函数(否则整个循环都是无操作),因此我更愿意假设顺序很重要(即不进行并行化)。 - 463035818_is_not_a_number
显示剩余3条评论

4
我个人喜欢使用一个小的帮助函数来完成这个任务。
template <typename F>
void repeat(size_t n, F f) {
  while (n--) f();
}

int main() {

   repeat(1000, [&] {
      testIteration();
   });
}

这样可以避免拼写变量名称的麻烦。但是当我需要变量名称时,我更喜欢使用view::iota。

话虽如此,有人告诉我这样写不易理解,每个人都读懂for循环,所以这可能是更好的选择。(当然,如果该函数被放在std命名空间中,则除外)。


1

除了我的解决方案非常简短之外,我知道这并没有提供与上面答案不同的内容。要重复代码2次,我使用如下循环:

for (auto _{2}; _--;) { /* this code gets repeated twice */ }

我认为使用前缀运算符会不够清晰,因为要重复两次代码,循环需要是:

for (auto _{3}; --_;) { /* this code gets repeated twice */ }

当然,小括号也可以代替大括号,例如:

for (auto _(2); _--) {}

0
仅供参考,这里有std :: generatestd :: generate_n可用,但仅适用于通过执行以下操作进行数组初始化:
int i = 0;
std::generate_n(myArray, 10000, [&]() -> int { return i++; });

-3

那么简单地定义一个宏怎么样呢? #define FOR(N, foo, ...) for (int _i = 0; _i < N; _i++) foo(__VA_ARGS__);

例如:

#include <iostream>

#define FOR(N, foo, ...) for (int _i = 0; _i < N; _i++) foo(__VA_ARGS__);

void bar(int a, int b)
{
    std::cout << "hello " << a+b << std::endl;
}

int main()
{
    FOR(5, bar, 12, 6);
    return 0;
}

输出:

hello 18
hello 18
hello 18
hello 18
hello 18

3
不。就是不行。 - Vinci

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接