1

In a long C++ function one common issue when reading the code is that there are often too many variables that potentially could be modified making it harder to keep track of them.

One typical case for me is where a variable is only used when initializing another, e.g, I want to keep a after this fragment, and "kill" x (and there are multiple such fragments):

...
extern int bar(int, int&);
int x=5;
const int a=bar(..., x);
// x is no longer used, but a is used
...

Note: I'm using variables of int-type to make the example self-contained, but in many cases they are class-object - with virtual functions, and in particular different classes for different fragments. Sometimes parts of x is used after the function call, and sometimes not - but unfortunately it's the same function bar so making it an out-argument isn't straightforward.

The following would be one obvious solution, but then a is no longer initialized and cannot be const.

...
int a;
{
   extern int bar(int, int&);
   int x=5;
   a=bar(..., x);
}
...

https://stackoverflow.com/a/15153194/5603247 indicates that another solution is to define and directly call a lambda:

...
const int a= [=](){
  extern int bar(int, int&);
  int x=5;
  return bar(..., x);
}();
...

Is this the best way to accomplish this? Are there any downsides?

As far as I can see there is no performance penalty - when optimization is enabled - https://godbolt.org/z/c1qn9M

Hans Olsson
  • 8,971
  • 12
  • 33
  • premise is that you do delcare `x` ? Otherwise you could just call `a = bar(...,5);` – 463035818_is_not_a_number Oct 28 '20 at 17:14
  • 2
    Say goodbye to fragments and say hello to functions. – Wyck Oct 28 '20 at 17:15
  • 2
    This is presumably because the second argument to `bar` is an _out_ variable? On the other hand, if it's not an out variable (I mean...x is not used after the function was called, so why bother?), then why is it not a const reference, and you could just say `bar(..., 5)`? – Wyck Oct 28 '20 at 17:19
  • 1
    This is very popular at the moment (even among people who accuse Lisp of having too many parentheses...) and I guess it is "best" on some scale until somebody comes up with something better. My personal opinion is that it can be good in small doses, but it is easy to get carried away and hide the code that actually does something among a bunch of boilerplate, making the code very hard to read. – molbdnilo Oct 28 '20 at 17:20
  • @Wyck right, I missed that it is a non-const reference. But I completely agree with you, if the caller doesn't bother about the modification i'd wrap it in a `int bar(int,int);` – 463035818_is_not_a_number Oct 28 '20 at 17:26
  • I tried to clarify the question a bit. – Hans Olsson Oct 28 '20 at 17:38
  • whether int or custom types does not change much. The actual problem in your examples is that `bar` takes an out-parameter but the caller does not want to use it as out-parameter. Out-parameters can be a bit annoying, if you dont care about the "out" then even more so. – 463035818_is_not_a_number Oct 28 '20 at 17:39
  • I updated again to try to address that. I will see if I can write a more complete example – Hans Olsson Oct 28 '20 at 17:43
  • feels like there is an issue in code that you didn't post and either you have problems to explain or i have problems to understand. The examples you did post are all fine as they are. I'd prefer the last, and when you do need `x` after the call then the whole point of the question is gone, because then .. you do need `x` after the call – 463035818_is_not_a_number Oct 28 '20 at 17:45

1 Answers1

3

If you do not care about modifications that bar is doing to the parameter then I would wrap the function:

int bar2(int x,int y) {
    return bar(x,y);
}

const int a = bar2(...,5);

No need to make the call itself more complicated than necessary. Otherwise using a immediately invoked lambda expression is a widely accepted pattern for complex initialization.

463035818_is_not_a_number
  • 64,173
  • 8
  • 58
  • 126