2

According to this Q&A, std::future works if a function returns a value, but you can't pass references and get multiple values. So a function like this will give no results with std::future:

void doSomething(int &a, int &b) { a = 1; b = 2; }

My idea was to create a structure and have the function return the structure:

#include <iostream>
#include <future>
using namespace std;

struct myData 
{ 
    int a; 
    int b; 
};

myData doSomething() 
{ 
  myData d; 
  d.a = 1;
  d.b = 2;
  return d;
}

int main() 
{
    future<myData> t1 = async(launch::deferred, doSomething); 

    printf("A=%d, B=%d\n", t1.get().a, t1.get().b);

    return 0;
}

So, how can I get two or more values from a std::future? Is there a better method than this?

Community
  • 1
  • 1
Mark Miles
  • 706
  • 8
  • 20
  • You need to understand the difference between a compiler error, which means your code is not valid C++ and must be fixed, and a linker error, which means the code was compiled successfully but the definition of some function or variable was not found. This is a linker error. – Jonathan Wakely Feb 12 '15 at 09:43
  • Yes, I'm sorry... I was testing this code on ideone.com that runs on Linux, while I usually test my code on Windows... – Mark Miles Feb 12 '15 at 09:49
  • I just edited my question cause the linker error was not the focus of my question. – Mark Miles Feb 12 '15 at 09:51
  • 2
    Unrelated to your linker error, but you can only `get()` from a future once. – T.C. Feb 12 '15 at 10:49
  • @T.C. thanks for this comment, this explains why, now that I'm tesing this future with my program, I am getting a runtime error. – Mark Miles Feb 12 '15 at 14:12

2 Answers2

4

but you can't pass references and get multiple values.

Not true, as explained in the answers to the linked question, you can pass references, you just need to use std::ref to protect them from decaying. So to call void doSomething(int &a, int &b) you would use:

int a;
int b;
auto fut = std::async(std::launch::deferred, doSomething, std::ref(a), std::ref(b));
fut.get();  // wait for future to be ready
std::printf("A=%d, B=%d\n", a, b);

But that function doesn't return multiple values, it uses out parameters to set multiple variables. For a function to return multiple values you do need to return some composite type such as a struct, but that has nothing to do with std::future, that's how C++ works. Functions have a single return type.

Your solution returning a struct is the idiomatic way, although your code will fail at run-time because you use t1.get() twice, and you can only retrieve the result from a std::future once. To access the result twice either move the result into a new variable:

auto result = t1.get();

or convert the future to a std::shared_future which allows the result to be accessed multiple times:

auto t2 = t1.share();

But you don't need to use a custom structure to return multiple values, you can just use a pair or tuple:

#include <cstdio>
#include <future>
#include <tuple>

std::tuple<int, int> doSomething() 
{ 
  return std::make_tuple(1, 2);
}

int main() 
{
    auto fut = std::async(std::launch::deferred, doSomething);
    auto result = fut.get();
    std::printf("A=%d, B=%d\n", std::get<0>(result), std::get<1>(result));
}
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
1

The error you get have nothing to do with your implementation, it's that the linker doesn't link with the pthread library by default.

Add the flagg -pthread to the compiler and linker (if you're using GCC or Clang) and it should work.

Alternatively, add the pthread library as a linker library with the -l linker flag.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Yes, that was a linker error that I did not recognize, but I have jus edited my post because the actual point of my question was whether that's the only valid method to retrieve multiple values from a function with std::future or there is a better known method that I'm totally ignoring... – Mark Miles Feb 12 '15 at 09:52
  • @MarkMiles In that case it's the normal way to return "multiple" values. You *can* use a functor (callable structure) or a lambda and pass a references, but to actually *return* multiple values using a structure is the only to do it. – Some programmer dude Feb 12 '15 at 09:55
  • 3
    N.B. sometimes just returning `std::pair` or `std::tuple<...>` is good enough and you don't need a custom structure – Jonathan Wakely Feb 12 '15 at 10:37
  • @JonathanWakely you could post this as an answer and maybe expand it with an example – Mark Miles Feb 12 '15 at 13:21