在C++中定义'for'循环宏

Define a 'for' loop macro in C++

本文关键字:循环 for C++ 定义      更新时间:2023-10-16

也许这不是好的编程实践,但是是否可以定义一个for循环宏?

例如

#define loop(n) for(int ii = 0; ii < n; ++ ii)

运行良好,但无法更改变量名ii

它可用于:

loop(5)
{
    cout << "hi" << " " << "the value of ii is:" << " " << ii << endl;
}

但是没有选择名称/符号ii

有可能做这样的事情吗?

loop(symbol_name, n)

其中程序员将符号名称插入" symbol_name "。

用法示例:

loop(x, 10)
{
    cout << x << endl;
}
#define loop(x,n) for(int x = 0; x < n; ++x)

在今天的C++中,我们不会为此使用宏,但我们会使用模板和函子(包括lambda的(:

template<typename FUNCTION>
inline void loop(int n, FUNCTION f) {
  for (int i = 0; i < n; ++i) {
    f(i);
  }
}
// ...
loop(5, [](int jj) { std::cout << "This is iteration #" << jj << std::endl; } );

loop函数在内部使用变量i,但 lambda 看不到这一点。这是loop的内部.相反,lambda 定义了一个参数jj并使用该名称。

除了 lambda,您还可以传递任何函数,只要它接受单个整数参数。您甚至可以传递std::to_string<int> - 并不是说loop会对生成的字符串执行一些有用的操作,但语法允许这样做。

[编辑]通过数学家;您可以使用以下方法支持不可复制的函子

template<typename FUNCTION>
inline void loop(int n, FUNCTION&& f) {
  for (int i = 0; i < n; ++i) {
    std::forward<FUNCTION>(f)(i);
  }
}

[编辑]2020 变体,在传递不适当的函数时应该提供更好的错误消息。

inline void loop(int n, std::invocable<int> auto&& f) {
  for (int i = 0; i < n; ++i) {
    std::invoke(f,i);
  }
}
#define loop(x, n) for(int x = 0; x < n; ++ x)

像这样的东西?

#include <iostream>
using namespace std;
#define loop(x, n) for(int x = 0; x < n; ++ x)
int main() {
    loop(i, 10)
    {
        cout << i << endl;
    }
    return 0;
}

可以将变量名称定义为宏的第一个参数:

#define loop(variable, n) for(int variable = 0; variable < n; ++variable )

请注意,大多数有经验的程序员都遵循一条规则 - 对宏使用大写标识符。在你的例子中,假设你有一个函数和宏:

#define loop(variable, n) for(int variable = 0; variable < n; ++variable )
void loop();

现在尝试在代码中调用该函数,并观察您收到哪些丑陋的错误消息。其中一些可能根本不容易理解。更糟糕的是,在命名空间或类的方法中具有该循环函数,并且根本没有帮助。

所以至少是这样:

#define LOOP(variable, n) for(int variable = 0; variable < n; ++variable )

但最好不要使用它。

#define loop(VARIABLE, n) for(int VARIABLE = 0; VARIABLE < n; ++ VARIABLE)

你可以试试这个。

使用:

#include <vector>
#include <cstdio>
using std::printf;
#define FOR(TYPE, IDENT, BEGIN, END) for(TYPE IDENT = BEGIN, IDENT##_end = static_cast<decltype(IDENT)>(END); IDENT < IDENT##_end; ++IDENT)
#define FOR_STEP(TYPE, IDENT, BEGIN, END, STEP) for(TYPE IDENT = (TYPE)(BEGIN), IDENT##_end = static_cast<decltype(IDENT)>(END); IDENT < IDENT##_end; IDENT += STEP )
#define FOR_ITER(IDENT, BEGIN, END) for(auto IDENT = BEGIN, IDENT_end = END; IDENT != IDENT_end; ++IDENT)
int main() {
  FOR(int, i, 0, 10) {
    printf("FOR i: %dn", i);
    printf("we can even access i_end: %dn", i_end);
  }
  FOR(auto, i, 0, 10) {
    printf("FOR auto i: %dn", i);
  }
  std::vector<int> vec = {4, 5, 7, 2, 3, 1, 4, 9, 8, 6};
  printf("FOR with iterator: {");
  FOR(auto, it, vec.begin(), vec.end()) {
    printf("%d, ", *it);
  }
  printf("}n");
  printf("FOR with non constant end:n");
  FOR(long, i, 0, vec.size()) {
    printf("vec[%ld] = %dn", i, vec[i]);
  }
  printf("n");

  // You can set a step size
  printf("FOR_STEP(double, d, 0, 20, 2.1): ");
  FOR_STEP(double, d, 0, 20, 2.1) {
    printf(" %f ", d);
  }
  printf("n");
  // It works with iterators that don't have "<" but only "!="
  // defined, but you probably want to use a range-based 'for' anyway.
  printf("FOR_ITER(auto, it, vec.begin(), vec.end()): ");
  FOR(auto, it, vec.begin(), vec.end()) {
    printf("%d, ", *it);
  }
  printf("n");
}

这是我能想到的最好的C++11目标。它确保END参数只计算一次,并要求beginend具有相同的类型,这几乎总是如此。

由于不应使用 ==!= 运算符测试双精度值,因此宏的默认FOR使用 < 运算符进行比较,这限制了迭代器对宏的使用,因为它们现在也需要定义<运算符。我无法想出一种适用于双迭代器和任意迭代器的解决方案;您可以选择一个更适合您需求的宏。

但是,您不应该在代码中引入所有宏,因为只有一个适合大多数需求的宏定义,代码将更具可读性。

在竞赛编程中,有必要尽可能快地编码。加快编码速度的一种方法是使用宏。竞赛程序员使用下面的宏来缩写"for loops":

#define For(i,j,n) for(int i=(j);i<((int)n);++i)

例如,下面的代码将打印 1 到 10。

#include <stdio.h>
#define For(i,j,n) for(int i=(j);i<((int)n);++i)
int main(void)
{
   For(i, 1, 11)
   {
       printf("%dt", i);
   }
}

但是宏是危险的,挑剔的,而且不是那么安全。我真的建议您不要在项目中使用它们。要显示此问题,请考虑以下代码。

#include <stdio.h>
#define For(i,j,n) for(int i=(j);i<((int)n);++i)
int main(void)
{
   int end = 10;
   For(i, 1, end++)
   {
       printf("%dt", i);
   }
}

如果运行代码,您将看到程序永远不会停止工作,尽管您可能期望输出应为 1 到 10。

用于双向 for 循环,它在一个宏中替换了for(auto i = 0; i < n; ++i)for(auto i = n - 1; i >= 0; --i)

你可以使用它,

#define F(i, st, n) for (auto i = st-(st > n); (i < n)^(st > n); i += 1-2*(st > n))

解释:如果开始 <= n,则i = st; i < n; i += 1否则i = st - 1; i >= n; i += -1

请注意,xor 运算符(i < n)^(st > n)适当地补充了函数。

或者,您也可以使用三元运算符(st > n)?(i >= n):(i < n)而不是异或运算符。喜欢这个

#define F(i, st, n) for (auto i = st-(st > n); (st > n)?(i >= n):(i < n); i += 1-2*(st > n))

由于时间开销最小,因此它应该同样有效地工作。

记得F(i, 0, m)F(i, m, 0)都包括0和排除m

尝试这样做- #define 循环(i,n( for((i( = 0;(一( <(国际((n(;(一(++(