I've got some code where I need to construct a local variable in a function, and pass it some arguments
void foo(...)
{
SomeObject var1(a, b, c());
}
This is all fine and dandy until I need multiple statements to construct the arguments. For example, I may need to process an array argument first
void foo(...)
{
std::vector<int> arg1;
while (condition)
process(arg1);
SomeObject var1(arg1, b, c());
}
This works, but it has the side effect of introducing the variable name arg1
into the function's scope. If I have to do this multiple times in a function, I need to be very careful with my variable names, and there's lots of opportunities to make hard-to-read errors.
In a perfect world I'd love to write
void foo(...)
{
{
std::vector<int> arg1;
while (condition)
process(arg1);
}
SomeObject var1(arg1, b, c()); // ILLEGAL: arg1 is not in scope
}
or
void foo(...)
{
{
std::vector<int> arg1;
while (condition)
process(arg1);
SomeObject var1(arg1, b, c());
}
...
doSomething(arg1, arg2, ...); // ILLEGAL: var1 is not in scope
}
Is there a way to construct var1
in the inner scope but make the resulting object available in the outer scope?
I am not aware of any way to do this, but I know there's about two pages worth of rules about extending the lifespan of temporaries using references, and they're really specific, so I'm curious if there's a trick to permit this pattern of packaging up variables in support of constructor arguments in a nested scope.
The closest I've gotten is using std::optional<SomeObject>
to declare the variable before the nested scope and assign to it inside the nested scope.
CodePudding user response:
While not yet standard (but supported by most compilers), you might use statement expressions for this:
SomeObject var1(({
std::vector<int> arg1;
while (condition)
process(arg1);
arg1;
}), b, c());
Until then, you can use an in-place lambda:
SomeObject var1([&](){
std::vector<int> arg1;
while (condition)
process(arg1);
return arg1;
}(), b, c());
CodePudding user response:
Using lambdas is one approach, one argument example below. Trivial to extend.
void bar(const std::vector<int>&){} // to prove the binding
void foo()
{
bar(
[]{std::vector<int> arg1; /*do stuff*/ return arg1;}()
);
}
I wouldn't recommend this for pre-C 17 though due to the potential for unwanted value copies being taken. A more conventional way perhaps is to use separate functions.