Declare uninitialized auto variables with type of Returning function

92 Views Asked by At

I am a fan of using auto as much as possible, but there's one scenario where so far I have no solution.

The scenario is where I have to declare the variable outside of a scope, but initialize it inside a scope, typically a try/catch. Here is a clasical example:

std::vector<std::shared_ptr<Some::Custom::Type> Initialize()
{
    return {};
}

void Use()
{
    // delctype(Initialize) result; // not working
    // auto result; // completely different
    std::vector<std::shared_ptr<Some::Custom::Type> result // so much typing
    try
    {
        result = Initialize();
    }
    catch(...) {}
    ....
    
}

PS. I know that you can avoid the issue by doing the rest of the code inside the try scope, but sometimes you need it like this. Is there a way to achieve delctype(Initialize) result; idiom in up to C++20?

2

There are 2 best solutions below

1
On

You basically have three approaches.

1. decltype

Give decltype an actual expression of the type your variable should have: delctype(Initialize()). Note: this is not always practical when the function takes a lot of parameters.

struct long_name {};

long_name initialize() { return {}; }

int main()
{
    decltype(initialize()) value;
    {
        value = initialize();
    }
}

(demo)


2. std::invoke_result

There is also std::invoke_result if you want to construct an elaborate trait.


3. Type alias

As an ultimate alternative, a type alias is sometimes the better solution:

using Types = std::vector<std::shared_ptr<Some::Custom::Type>;
3
On

decltype(Initialize) is the type of the function. You want decltype(Initialize()) to get the type of the expression Initialize(), which is simply the return type:

decltype(Initialize()) result;

You might also use an immediately invoked lambda:

auto result = []{
    try
    {
        return Initialize();
    }
    catch(...) {}
}();

Demo

Other options include making a type alias to shorten it, using std::invoke_result (though I don't think this has any benefit over decltype in this context), or, as you mention, having the rest of the code inside the try block; you can even put the entire function inside with a function-try-block.