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?
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.
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.
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”.
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.
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).
I prefer,
std::tuple<bool, std::string, int> f() { ... return { false, "home", 0 }; }
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.
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 }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With