Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to return a tuple from function in C++11?

I want to return some values from a function and I want to pack it in a tuple. So I have two possibilities for function declaration:

std::tuple<bool, string, int> f() {   ...   return std::make_tuple(false, "home", 0); } 

and

std::tuple<bool, string, int> f() {   ...   return std::forward_as_tuple(false, "home", 0); } 

These functions are equivalents? Between these functions which do you prefer?

like image 326
Gian Lorenzo Meocci Avatar asked May 23 '13 11:05

Gian Lorenzo Meocci


People also ask

How do you return a tuple from a function in C++?

While C++ does not have an official way to return multiple values from a function, one can make use of the std::pair , std::tuple , or a local struct to return multiple values.

How do I return a tuple?

That's because you can return a tuple by separating each item with a comma, as shown in the above example. “It is actually the comma which makes a tuple, not the parentheses,” the documentation points out. However, parentheses are required with empty tuples or to avoid confusion.

Can we return 2 values from a function in C++?

In C or C++, we cannot return multiple values from a function directly. In this section we will see how to use some trick to return more than one value from a function. We can return more than one values from a function by using the method called “call by address”, or “call by reference”.

Why does my function return a tuple?

Python functions can return different values, objects, and types. So Python functions can return tuples without a problem. What makes returning a tuple from a function is popular than returning the types is multiple values or objects can be returned by using a tuple.


2 Answers

std::forward_as_tuple() creates a tuple of references. Since you are returning a tuple<bool, string, int> anyway, the two end up being equivalent in this case, but I think the first approach is clearer - using forward_as_tuple() when you are not forwarding anything is confusing.

Also, as mentioned by Sebastian Redl in the comments, make_tuple() would allow the compiler to perform copy elision - per paragraph 12.8/31 of the C++11 Standard, while forward_tuple() would not (since what it returns does not have the same type as the function's return type).

like image 54
Andy Prowl Avatar answered Sep 28 '22 15:09

Andy Prowl


I prefer,

std::tuple<bool, std::string, int> f() {   ...   return { false, "home", 0 }; } 

EDIT 1

The above code is actually compiling for me under clang/libc++ trunk. As @AndyProwl commented in comments section, this shouldn't since std::tuple constructor is explicit and returning through initialization-list syntax is in copy-initialization context, hence copy-list-initialization, which fails when an explicit constructor is matched.

I don't know the reason why clang/libc++ is passing, I suppose it to be a bug in libc++. Anyway, it's sad one can't do that for tuples...

I think I realized how sad (for me, at last) it's, generally. I was becoming used to that syntax, but one is forced to know beforehand whether or not the returning type contains an explicit constructor anytime for it to work.

EDIT 2

This is indeed a libc++ extension, for more information, checkout Howard Hinnant answer here: https://stackoverflow.com/a/14963014.

It's also currently open in the libc++ bug list: http://llvm.org/bugs/show_bug.cgi?id=15299.

This is the relevant proposal: Daniel Krügler, Improving pair and tuple.

In short this is what happens with libc++:

#include <tuple> #include <string>  struct S {     explicit S(int) {} };  int main() {     std::tuple<int, std::string> t1 = { 1, "hello" }; // ok     std::tuple<std::string> t2      = "hello";        // ok     std::tuple<int, S> t3           = { 1, 1 };       // fail: an *element* is to be constructed explicitly } 
like image 20
pepper_chico Avatar answered Sep 28 '22 16:09

pepper_chico