1

I have a member function that needs to return multiple references of char member variables.

class Foo {
public:
    Foo() {// ... constructor }
    
    std::string& func();

private:
    char ch1 = 'a', ch2 = 'b', ch3 = 'c';
};

The code below is something would obviously not fulfill my purpose, because the lifetime of the local variable is limited to the scope of the function call:

std::string& func()
{
    std::string total = "";
    total += this-> a;
    total += this-> b;
    total += this-> b;
    
    return total;
}

I would also prefer not to use the method of allocating memory for the local variable using new, then having to delete it after.

I also would not prefer to add a new member variable to the class that is used in the member function and returned.

First of all, is doing this even possible? If so, how can I achieve this?

Many thanks for help.

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
Amolgorithm
  • 697
  • 2
  • 20
  • 1
    Does this answer your question? [Returning multiple values from a C++ function](https://stackoverflow.com/questions/321068/returning-multiple-values-from-a-c-function) – BoP Jul 04 '23 at 20:22
  • It's not entirely clear what you actually want to return, here, but maybe define a custom class that has references to each of the desired values and return that? (I was going give the same link as @BoP!) – Adrian Mole Jul 04 '23 at 20:23
  • @BoP Yeah, I saw that one. No, unfortunately, it did not answer my question. – Amolgorithm Jul 04 '23 at 20:23
  • 5
    It might be a good idea too state what you actually want to do, because this feels like an XY problem – infinitezero Jul 04 '23 at 20:28
  • 1
    once you returned a non-const reference to a private member you can as well make it public. its not encapsulation anyhow – 463035818_is_not_an_ai Jul 04 '23 at 20:31
  • 1
    In particular, I suspect that a friend class or function could be what you're actually looking for. – infinitezero Jul 04 '23 at 20:36
  • I'm really confused why you show code that builds a `std::string` and then conclude that the only problem is a reference to local (easy to fix, just return by value), and how that `std::string` return by reference is supposed to illustrate a question about returning 3 references. I'm also confused why you think you can use variable contents (`'a'`, `'b'`) to find member variables (`ch1`, `ch2`) – Ben Voigt Jul 04 '23 at 21:09
  • NO do NOT return references to local variables your `func()` returns a dangling reference and is going to break your program (UB). As for the solution just define a struct with 3 references in it and return that. Simple and unlike std::tuple has some semantic meaning as well. – Pepijn Kramer Jul 05 '23 at 03:56

1 Answers1

2

You can return a std::tuple of references :

std::tuple<char&, char&, char&> foo::func()
{
    return std::tie(ch1, ch2, ch3);
}

You can also use structured binding to unpack the return value :

int main()
{
    foo f;
    auto [a, b, c] = f.func();
    b = 'z';    // Modifies `f.ch2`
}

Live example : https://godbolt.org/z/eM1h6qaxx


Edit for C++14 :

Instead of structured binding, you can use std::get to access one of the return values :

int main()
{
    foo f;
    auto result = f.func();
    std::get<1>(result) = 'z';    // Modifies `f.ch2`
}

C++14 live example : https://godbolt.org/z/jrjsr4K7e

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
  • +1 Good answer. I probably should have mentioned in the question that I am using C++ 14. I believe structured binding is C++ 17? Do you have an alternative for this? – Amolgorithm Jul 04 '23 at 20:28
  • 3
    I'm confused. This is essentially the same answer as the suggested dupe in comments, which you said did not answer your question. – Chris Jul 04 '23 at 20:30
  • 2
    @Chris I think the difference is the dupe does not address the concern of returning references. – François Andrieux Jul 04 '23 at 20:34
  • @FrançoisAndrieux Why use a tuple if all members are the same type? Is this not possible with any data structure. Does tuple hold any benefits? – Amolgorithm Jul 04 '23 at 20:50
  • 1
    @Amolgorithm You could just create a `struct mytuple { char &x, &y, &z; }` if you'd like. You'd have to specialize `std::get` if you want to use that though, but you could use the members directly: [example](https://godbolt.org/z/feaMjojqK) – Ted Lyngmo Jul 04 '23 at 20:51
  • 1
    @Amolgorithm Sorry, I did not understand what clarifications you are asking for. The benefit of using `std::tuple` over other solutions is that every part you need for an efficient and clear implementation are provided by the standard library. – François Andrieux Jul 04 '23 at 21:01
  • _"Why use a tuple if all members are the same type"_ - Are you perhaps asking why we can't use an array? If so, the answer is that arrays of references are not permitted. – Ted Lyngmo Jul 04 '23 at 21:03
  • @TedLyngmo Can you not use `std::reference_wrapper` though? – Amolgorithm Jul 04 '23 at 21:08
  • @Amolgorithm Yes, a `reference_wrapper` just stores a pointer internally and provides reference-like access. You'd have to store them in a `std::array` or similar to return them. It will not provide any benefits here as I can see. [example](https://godbolt.org/z/qbM1c8jaM) – Ted Lyngmo Jul 04 '23 at 21:11
  • @Amolgorithm: Why use three `std::reference_wrapper` and a container to put them in, when a single `std::tuple` will do? Are you wishing that you could dynamically iterate and/or index the results? An array of pointers would work admirably then. – Ben Voigt Jul 04 '23 at 21:11
  • @BenVoigt Why need three though? Can't you do it with one `std::reference_wrapper`? As shown [here](https://www.geeksforgeeks.org/reference_wrapper-in-cpp/). – Amolgorithm Jul 04 '23 at 21:13
  • @Amolgorithm You have three references? The example in the link is an array of 5. You can't return arrays - so you need to package them like I showed above. – Ted Lyngmo Jul 04 '23 at 21:14
  • @Amolgorithm The linked example shows an array of `std::reference_wrapper`. There is one `reference_wrapper` for each of those `char`. Notice the `[]` at the end of `ref[]`. – François Andrieux Jul 04 '23 at 21:27