6

Is there any way of doing parallel assignment in C++? Currently, the below compiles (with warnings)

#include <iostream> 

int main() { 
  int a = 4;
  int b = 5;
  a, b = b, a;
  std::cout << "a: " << a << endl
            << "b: " << b << endl;

  return 0;
}

and prints:

a: 4
b: 5

What I'd like it to print ... if it weren't obvious, is:

a: 5
b: 4

As in, say, ruby, or python.

Nick
  • 389
  • 2
  • 10

6 Answers6

16

That's not possible. Your code example

a, b = b, a;

is interpreted in the following way:

a, (b = b), a

It does nothing. The comma operator makes it return the value of a (the right most operand). Because assignment binds tighter, b = b is in parens.

The proper way doing this is just

std::swap(a, b);

Boost includes a tuple class with which you can do

tie(a, b) = make_tuple(b, a);

It internally creates a tuple of references to a and b, and then assigned to them a tuple of b and a.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
4

Parallel assignment is not supported in C++. Languages that support this usually treat a,b,c as a list on either side of the assignment operator, this isn't the way the comma operator works in C++. In C++, a, b evaluates a and then b, so a, b = b, a is the same as a; b = b; a;.

Robert Gamble
  • 106,424
  • 25
  • 145
  • 137
1

Or Perl. But no, it's not possible (as far as I'm aware), you need to use a temporary variable, as in:

int a = 4;
int b = 5;

{
    int tmp = a;
    a = b;
    b = tmp;
}

FYI, internally those languages (or Perl atleast) create a temporary list { a, b }, then assign the list to the two variables. In other words, this is atleast as performant, if only a little more messy.

Matthew Scharley
  • 127,823
  • 52
  • 194
  • 222
1

This question is very old – I just stumbled into it today...
...and wondered why nobody gave this answer before...

I think, it's possible to do it in C++11 similar like Python does it (under the hood):

#include <iostream>
using namespace std;

int main()
{
  int a = 4, b = 5;
  cout << "Before assignment: a: " << a << ", b: " << b << endl;
  pair<int&, int&> ba(b, a);
  ba = make_pair(a, b); // <===: (b, a) = (a, b)
  cout << "After assignment : a: " << a << ", b: " << b << endl;
  return 0;
}

I tried this out on ideone.com. The output was:

Before assignment: a: 4, b: 5
After assignment : a: 5, b: 4

If I remember right (I'm not a Python expert), in Python, a, b denotes a pair. (Python Doc.: 5.3. Tuples and Sequences)

Such pair can be done in C++ 11 easily e.g. with std::pair. In this case, I made a pair of references and assigned the pair of values. It works as the make_pair() loads both variables before the right pair (of values) is assigned to the left pair of references.

Scrolling again, I realize that this answer is close to the boost based solution of Johannes answer.

May be, the reason is that it didn't work in C++03. I tried in coliru.stacked-crooked.com: With -std=c++03 it yields terrible to read compiler errors – changing to -std=c++11 and it compiles and executes fine as described above.

Disclaimer

I just cannot imagine what this solution is good for nor what practical worth it may have. This is not what I tried to do. As many other answers states "It does not work." IMHO it does (spelling it right according to the C++ language)...

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56
0

Or Lua...
There are tricks with C/C++, like using xor or operations, but with risk of overflow and such. Just do it the painful way, with three assignments. Not a big deal.

PhiLho
  • 40,535
  • 6
  • 96
  • 134
  • might want mention the xor trick also only works on integral types. Also, integer promotion would keep it from overflowing but two of the same type won't overflow with a xor operation 0b1110 xor 0b1010 will always be 0b1100 at it is a bitwise operation – Beached Oct 12 '17 at 02:56
0

There is no such function in the Standard Library. You could write a set of template functions :

template <typename T1> void ParAssign(T1& Lhs_1, T1 const& Rhs1);
template <typename T1, typename T2> void ParAssign(T1& Lhs1, T2& Lhs2, T1 const& Rhs1, T2 const& Rhs2);
// etc.
ParAssign(a,b,
          b,a);

That's non-trivial if there is aliasing, as in your swap example.

MSalters
  • 173,980
  • 10
  • 155
  • 350