How to initialise variables of returning tuple in c++?

Viewed 327

I have a function xyz() which returns an tuple<std::string, double>. When I call this function individually, I can do the following:

auto [tresh, loss] = xyz(i);

This results in no error, but if I want to use the xyz() function in an if else block, then I can not use the tresh and loss variables anymore in the following code. Example:

if (boolX) {
        auto [tresh, loss] = xyz(i);
    } else {
        auto [tresh, loss] = xyz(j);
    }
std::cout << tresh << std::endl;

I also tried to initialise the tresh and loss variable before the if else block and remove the auto, but this gives the following error:

Expected body of lambda expression

How to resolve this?

6 Answers

Depending on the exact code, you could replace with a ternary

auto [tresh, loss] = boolX ? xyz(a) : xyz(b);
std::cout << tresh << std::endl;

Before structured bindings were created, std::tie was the solution for unpacking tuples.

std::string tresh;
double loss;
if (boolX) {
    std::tie(tresh, loss) = xyz(i);
} else {
    std::tie(tresh, loss) = xyz(i);
}
std::cout << tresh << std::endl;

It was considered clunky, because you have to declare variables before initialization, but that's exactly what you want here.

You can use a lambda for it:

auto [tresh, loss] = [&boolX, &i, &j](){
    if (boolX) {
        return xyz(i);
    } else {
        return xyz(j);
    }
}();
std::cout << tresh << std::endl;

You could do something like this:

std::tuple<std::string, double> results;
if (boolX) {
    results = xyz(i);
}
else {
    results = xyz(j);
}
auto [tresh, loss] = results;
std::cout << tresh << std::endl;

You need to declare the two variables outside of the individual cases to access them outside. You can use std::tie to "tie" the two together:

#include <iostream>
#include <tuple>
#include <string>
std::tuple<std::string,double> xyz() { return {"foo",1.0}; }

int main() {
    std::string a;
    double b;
    bool condition = false;
    if (condition) {
        std::tie(a,b) = xyz();
    } else {
        std::tie(a,b) = xyz();
    }
    std::cout << a << " " << b;
}

You might restructure you code, so you do the job in its branch:

if (boolX) {
    auto [tresh, std::ignore] = xyz(i);
    std::cout << tresh << std::endl;
} else {
    auto [tresh, std::ignore] = xyz(j);
    std::cout << tresh << std::endl;
}

You might argue than code is longer, so make an extra function or lambda:

const auto do_job = [](auto&& p)
{
    auto [tresh, std::ignore] = p;
    std::cout << tresh << std::endl;
}
if (boolX) {
    do_job(xyz(i));
} else {
    do_job(xyz(j));
}
Related