Home > other >  Constructing C object using variables from an inner scope... can it be done?
Constructing C object using variables from an inner scope... can it be done?

Time:07-02

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.

  •  Tags:  
  • c
  • Related