1

I'm relatively new to C++ and I'm currently creating a class based on a C code I was given. In this code there are some macros that define for loops. I've heard that is better to avoid macros so I'm trying (and failing) to write them differently.

I looked at this question which suggest the use of templates and functors, even though I'm not achieving what I want.

I will give a simplify example. Let's suppose that the macro is defined as

#define for_loop (g,u,v) \
for (u = g.attribute, v = g.otherAttribute ; u <= 20 ; u = g.updateAttribute, v = g.updateOtherAttribute)

And it is used in several parts of the code for different purposes.

How would you implement it without using macros in C++?

esv
  • 41
  • 1
  • 5
    Macros are just text-replacements. The example you've given is hard to reason about without more context. What you could do is simply not use the macro and just write out the for-loop. You don't save much and it's much clearer what you're trying to do. – Ted Klein Bergman Nov 10 '20 at 10:14
  • 3
    The best way to avoid macros is to just not use them, and instead write C++ code. Why can't you do that here? If this needs to be generic code, consider using a [template function](https://en.cppreference.com/w/cpp/language/templates). When combined with things like [lambda expressions](https://en.cppreference.com/w/cpp/language/lambda) you can do a ton without ever having to even think about macros. – tadman Nov 10 '20 at 10:19
  • Show the definition of the type of a typical `g` (do you have many different types with these attributes?) and an example of the body of that loop. – Ted Lyngmo Nov 10 '20 at 10:24

2 Answers2

2

First of all, if you look for "dumb" replacement for these macros, then you may be better off to just leave them alone.

If you really look for better readability of code, try to find meaningful idioms, that may not map one to one to these macros. I.e. maybe sometimes this for_loop() can be replaced with range-for loop, something like:

for (auto u : g) {
  ...
}

And sometimes may be it may be replaced with call to some standard functions like std::find() or something...

If you want to implement function that would do exactly what this macro do you can do something like this:

void for_loop(g_type g, u_type u, v_type v, std::function<void(u_type, v_type)> func) {
  for (u = g.attribute, v = g.otherAttribute ; u <= 20 ; u = g.updateAttribute, v = g.updateOtherAttribute)
  {
    func(u, v);
  }
}

And then use it like this:

  for_loop(g, u, v, [<may require capture some used vars here>](u_type u, v_type v)
  {
    ... some code ...
  });

instead of original

  for_loop(g, u, v)
  {
    ... some code ...
  }

If changes to g, u or v should be visible after loop, then references should be used instead of passing by value.

But I highly don't recommend this approach.

sklott
  • 2,634
  • 6
  • 17
1

How would you implement it without using macros in C++?

You can write a function template:

void
for_loop (auto& g, auto& u, auto& v, const auto& body)
{
    for (u = g.attribute, v = g.otherAttribute;
         u <= 20;
         u = g.updateAttribute, v = g.updateOtherAttribute)
        body(g, u, v);
}

The details may be different depending on how the macro is used. This example follows the macro closely, but there may be a better way to express the operation. I recommend more meaningful parameter names.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • How is `auto` allowed in function parameters? It doesn't compile with msvc –  Nov 10 '20 at 10:49
  • @AryanParekh It's a C++20 thing. You can replace them with explicit template type parameters in older versions. – eerorika Nov 10 '20 at 10:50
  • Oh okay, I was really confused to see `auto` that's why I asked :) –  Nov 10 '20 at 10:51
  • @AryanParekh: If you don't need `u` and `v` outside the function, you can simplify this by making the local variables of the function instead of arguments. – MSalters Nov 10 '20 at 11:54