return 2 values

Is there a more efficient way to return two values from a function?

If two values must be returned. I add the two values then return it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int mustReturnTwoValues(int x, int y)
{
    return x + y;
}

int main(){
   int sum, x1 = 1, x2 = 3;
   while(1){
       sum = mustReturnTwoValues(x1,x2);
       if(sum == 3){
           x1 = 1; x2 = 2;
           x1++; x2++; 
       }
       else if( sum == //any sum){
           //assign value to x1 and x2 then increment
       }
       //else if ..... many more else if....
   }
   return 0;
}


What is the proper way in returning two values?
Thanks.
You can't return two values simultaneously. You can return one expression and one expression only.
I consider this a messy solution, personally, but you could define a class containing members of the types you wish to perform. You can also return an array if they are the same type but I'm not sure how that would turn out.
In general, you would pass the second variable as a non-const reference and modify its value.
In addition, you could return a collection if they are all the same type, or a std::pair, or a boost::tuple.
boost has a tuple?
(Of course, boost has everything.)
Heh, heh, heh:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// this demonstrates returning two values from a function
//

#include <iostream>
#include <map>
#include <string>

using namespace std;

// Our template functor
template <typename T1, typename T2>
struct t_unpair
  {
  T1& a1;
  T2& a2;
  explicit t_unpair( T1& a1, T2& a2 ): a1(a1), a2(a2) { }
  t_unpair<T1,T2>& operator = (const pair<T1,T2>& p)
    {
    a1 = p.first;
    a2 = p.second;
    return *this;
    }
  };

// Our functor helper (creates it)
template <typename T1, typename T2>
t_unpair<T1,T2> unpair( T1& a1, T2& a2 )
  {
  return t_unpair<T1,T2>( a1, a2 );
  }

// Our function that returns a pair
pair<int,float> dosomething( char c )
  {
  return make_pair<int,float>( c*10, c*2.9 );
  }

// And how we test the pair.
int main()
  {
  int   a;
  float b;
  unpair( a, b ) = dosomething( 'A' );
  cout << a << ", " << b << endl;

  return 0;
  }

:-)
@Duoas: Bravo! Now write that for an n-arity tuple. :-)
There is, a return value will only return 1 value; consider the following:

1
2
3
4
5
6
7
int whatever(int list)
{
    int something = 9;
    if(whatever < statement + something)
        whatever = something;
    return whatever * 23, something + 13, whatever;
}


This block will only return whatever.

"By definition, a value-returning function only returns a single value; this value is returned by the return statement. If a function needs to return more than one value, you should change it to a void function and use the appropriate reference parameters to return the values."

C++ Programming - D.S. Malik
I see.
Thanks to all especially to Duoas.

By the way I solved my problem.
I made two functions instead of one.
Then return one value per function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int mustReturnFirstValue(int x, int y)
{
    //do something here with x and y;
    return x;
}
int mustReturnSecondValue(int x, int y)
{
    //do something here with x and y;
    return y;
}
int main(){
   int retx, rety, x1 = 1, x2 = 3;
   retx = mustReturnFirstValue(x1, x2);
   rety = mustReturnSecondValue(x1,x2); 
   return 0;
}
That's not an ideal solution. Duplicate code is problematic.

I don't really understand why such a situation would ever be necessary. It seems to me you're misunderstanding the point of return values.
Yeah that's not an ideal solution.

but I'm still working on it.

For now, I will try the code posted by Duoas.
I find it hard to insert since I was using classes.

wait for my update.

Thanks.

EDIT: oh! I think I must use utility library for pair method.
then return the pair? wait I'll try.

Last edited on
@Duoas
Thanks for the code. I can now finally return 2 values using the code you posted with only 363 lines compared to the first algorithm I made with 403 lines.

@all
Thanks.
@PanGalactic
Well, it can be written for an n-arity tuple in C++0x, but I'm not sure it is worth the time.

The problem with these kinds of things is that it just multiplies code to do something you can do without.

Sure, templates are pretty, and they satisfy some people's wants for genericity and functional programming, but they really aren't much better than macros.

For every permutation of template arguments you use this trick on, you produce two functions and a structure in your code (the class has one function and one inline ctor), in addition to the functions whose results you wish to unpack. Rather wasteful, no?

The C++0x code to handle any arbitrary tuple would be an order of magnitude worse, since it would have to be done with a recursive template!


@yoked88
Another young mind ruined by Malik. Consider the following: Two posts before yours I had already posted code that contradicts the assertion in your post, which within the context of this thread cannot be anything other than 'it is not possible to return more than one value.'

Oh, and abusing the language to prove an (incorrect) point doesn't prove anything. The comma operator in your example did exactly what it was supposed to do, and it didn't do what it is not supposed to do. You cannot claim the car failed to operate properly with "it didn't go when I pressed on the brake."

Seriously, even though I haven't read his stuff, any time someone posts with references to Malik's C++ books it is usually something that makes me dislike them even more.

Here is my (humble) advice to you. Pay attention instead of regurgitating. You'll learn more that way.


@olredixsis
Personally, I like being able to say, as in Python, things like:
 
 x, y = myfunc( 12 )

It is very succinct and clear that "myfunc" returns not one, but two --count 'em!-- two values. Hence, my old little experiment with:
 
 unpair( x, y ) = myfunc( 12 );

That said, it is not in line with the way the language is designed. The best way to do it is as Mr. Malik (ugh) correctly suggested:
 
 myfunc( x, y, 12 );

Unfortunately, this now becomes ambiguous as to what is happening, unless you've read the documentation to "myfunc" which says something useful like:
 
 void myfunc( int& a, float& b, char c )
or if you are lucky, a comment like:
 
  // Returns a and b given c 

At least in C you always knew when something was afoot, since those silly '&'s were not yet banished from calling code:
 
 myfunc( &x, &y, 12 );  /* woah... something must happen to x and y here! */


Even so, this is the more correct solution because it reduces bloat and complexity. Related code is still properly modularized in one function, type errors are not compromised, and the code is still succinct and quick. That is, this is really the most efficient way to do it.

Hmm, I just thought of another experiment which may be both efficient and simple, with the ability to extract any n-tuple expressed as a struct or maybe a pair<> list.

I'll post back a little later.
Duoas wrote:
Sure, templates are pretty, and they satisfy some people's wants for genericity and functional programming, but they really aren't much better than macros.

I agree with your sentiment. There are areas of Boost I won't touch because the developers are mad with TMP-fever.
Last edited on
Duoas, that's pretty cool!

Small note: I think line 35 should could read:
 
return make_pair( c*10, c*2.9 );


Unless it has to be specified to match up with the return value. I suppose if that were the case, then it could just be pair rather than make_pair.

Well, then again, the function could be a template...I guess I'm just talking to myself.
Last edited on
Heh, well then, here's a n-ary solution using an improper list of std::pair<>s. (It would work just as well with a proper list, but that isn't generally useful in C++.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <utility>

//----------------------------------------------------------------------------
// This first one handles the case that we are decoding a
// nested pair (a list).
// It assigns the car to the argument,
// and returns the cdr, which must be a pair (or list).
template <
  typename FirstType, 
  typename SecondType1,
  typename SecondType2
  >
inline
const std::pair <SecondType1, SecondType2>
operator >> (
  const std::pair <FirstType, std::pair <SecondType1, SecondType2> > & xs,
  FirstType                                                          & extract
  ) {
  extract = xs.first;
  return    xs.second;
  }

//----------------------------------------------------------------------------
// This second one is if we are decoding a pair only (not a list).
// In this case, we want to prevent the result from degenerating
// into a non-pair object (which we cannot handle with our overloaded
// operator>>), so we recouple the cdr into the head of a new pair,
// which can be recursively handled by this same function.
template <
  typename FirstType,
  typename SecondType
  >
inline
const std::pair <SecondType, int>
operator >> (
  const std::pair <FirstType, SecondType> & xs,
  FirstType                               & extract
  ) {
  extract = xs.first;
  return std::make_pair <SecondType, int> ( xs.second, 0 );
  }
And an example that uses it:
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <iostream>
#include <sstream>
#include <string>
using namespace std;

//----------------------------------------------------------------------------
// This is our function that returns an improper list (or tuple) of:
//   <int, float, char>
pair <int, pair <float, char> >
fn( const char* s )
  {
  int   a;
  float b;
  char  c;

  istringstream ss( s );
  ss >> a;
  ss >> b;
  ss >> ws;
  ss >> c;

  return make_pair( a, make_pair( b, c ) );
  }

//----------------------------------------------------------------------------
int main()
  {
  int   age;
  float height;
  char  gender;

  // And here we use our fancy-pants operator overloads to
  // do the dirty work of getting the pieces out of the list.
  //
  fn( "35 5.83 M" ) >> age >> height >> gender;

  cout <<   "age    = " << age
       << "\nheight = " << height
       << "\ngender = " << gender
       << endl;

  return 0;
  }

Keep in mind, this solution has the same drawbacks as did the first one I posted.

However, it does have the very nice advantage that it is not restricted to a specific number of items to untuple.

It also has type safety: if you try to untuple an argument with the incorrect type, the compiler will complain at you. (Voluminously.)


And, to round it off, here's a very simple solution which incurs only one --count 'em-- one additional function, but remains just as readable (and gives you more comprehensible error messages to boot):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <sstream>
#include <string>

//----------------------------------------------------------------------------
struct fn1_returns
  {
  int   a;
  float b;
  char  c;

  fn1_returns( int a, float b, char c ): a( a ), b( b ), c( c ) { }

  void returns( int& ra, float& rb, char& rc )
    {
    ra = a;
    rb = b;
    rc = c;
    }
  };

//----------------------------------------------------------------------------
fn1_returns fn1( const char* s )
  {
  int   x;
  float y;
  char  z;

  std::istringstream ss( s );
  ss >> x;
  ss >> y;
  ss >> std::ws;
  ss >> z;

  return fn1_returns( x, y, z );
  }

//----------------------------------------------------------------------------
int main()
  {
  using namespace std;

  int   age;
  float height;
  char  gender;

  fn1( "35 5.83 M" ).returns( age, height, gender );

  cout <<   "age    = " << age
       << "\nheight = " << height
       << "\ngender = " << gender
       << endl;

  return 0;
  }

Sweet!
Topic archived. No new replies allowed.