user9590073
user9590073

Reputation:

Can a function return multiple values of varying types?

It thought it would be interesting to return multiple values (with different types!) from a C++ function call.

So I've looked around to maybe found some example code but unfortunately I could not find anything matching to this topic.

I'd like a function like ...

int myCoolFunction(int myParam1) {
    return 93923;
}

to work on different types to return multiple different types of values like

?whatever? myCoolFunction(int myParam1) {
    return { 5, "nice weather", 5.5, myCoolMat }
}

So is something like this possible using C++ (My idea was to use a special AnyType-vector but I could not find example code therefore) or do I have to stay on these type of call? (see below)

void myCoolFunction(cv::Mat &myMat, string &str){
   // change myMat
   // change str
}

Note: So the order and the count of the returned element will be the same every time - > The set stays identical (like 1.:double, 2.:int in every case)

Upvotes: 3

Views: 4039

Answers (5)

einpoklum
einpoklum

Reputation: 132240

Yes, a function can return multiple types of different values, within an std::tuple, available in the standard library since C++11:

#include <tuple>

std::tuple<int, std::string, double, cv::Mat>
myCoolFunction(int myParam1) {
    return { 5, "nice weather", 5.5, myCoolMat }
}

If you're allowed to use C++14 code, you don't even have to declare the type:

#include <tuple>

auto myCoolFunction(int myParam1) {
     return std::make_tuple(5, "nice weather", 5.5, myCoolMat);
}

and here is proof both of these versions compile (sans the cv::Mat - I don't think GodBolt has that available).

Notes:

  • If you use std::make_tuple, the types might not be exactly what you expect. For example, in this case you'll get a char * although when defining the tuple explicitly you could force it to be std::string like I have above. This is usually not a problem.
  • If some of the data is large, you might try to std::move it, to avoid copying the whole thing, e.g. passing std::move(myCoolMat).

Upvotes: 3

Holt
Holt

Reputation: 37686

If you want to return multiple values, you can return an instance of a class wrapping the different values.

If you do not care about losing semantics, you can return a std::tuple1:

auto myCoolFunction(int myParam1) {
    return std::make_tuple(5, "nice weather", 5.5, myCoolMat);        
}

If you want to force the types (e.g., have a std::string instead of a const char *):

std::tuple<int, std::string, double, cv::Mat> myCoolFunction(int myParam1) {
    return {5, "nice weather", 5.5, myCoolMat};
}

In both cases, you can access the values using std::get:

auto tup = myCoolFunction(3);
std::get<0>(tup); // return the first value
std::get<1>(tup); // return "nice weather"

1 If you have a C++17 compliant compiler, you can make use of template argument deduction and simply return std::tuple{5, "nice weather", 5.5, myCoolMat}.

Upvotes: 4

manglano
manglano

Reputation: 844

Returning a std::vector of std::variant, where std::variant is template parameterized to your selection of types. If any type is actually possible, I'm not sure why you're doing that with structures and not simply writing to the memory space; not having a deterministic concept of the objects and types in the structure has low value.

Upvotes: -4

Abhishek Keshri
Abhishek Keshri

Reputation: 3244

You can return a structure or use std::tuple.

Using struct, you can do:

myStruct create_a_struct() {
  return {20, std::string("baz"), 1.2f};
}

And with std::tuple

std::tuple<int, std::string, float> create_a_tuple() {
  return {20, std::string("baz"), 1.2f};
}

Upvotes: 2

Bathsheba
Bathsheba

Reputation: 234875

(Answer for amusement really and to demonstrate the power of C++ rather than anything else.)

One way, which is really rather evil since you burden the call site with unpicking the contents is to use

std::shared_ptr<void>

as the return type. This is allowed since std::shared_ptr supports type erasure. (Unfortunately, std::unique_ptr doesn't so you have to rule that out.)

Clearly though, in the function, you'll need to use std::make_shared or similar.

Reference: Why is shared_ptr<void> legal, while unique_ptr<void> is ill-formed?

Upvotes: 0

Related Questions