12

I was trying to swap two variables using std::tie() as per the following code (I am aware of std::swap, I was just trying this out of curiosity):

#include <iostream>
#include <tuple>

using std::cin; using std::tie; 
using std::cout; using std::endl;
using std::make_pair;

int main() {
    int a = 2, b = 10;
    cout << "Before Swapping using {}" << endl;
    cout << "a: " << a << " b: " << b < <endl;
    tie(a, b) = {b, a};
    cout << "After Swapping using {}" << endl;
    cout << "a: " << a << " b: " << b << endl;

    a = 2, b = 10;
    cout << "Before Swapping using make_pair()" << endl;
    cout << "a: " << a << " b: " << b << endl;
    tie(a, b) = make_pair(b, a);
    cout << "After Swapping using make_pair()" << endl;
    cout << "a: " << a << " b: " << b << endl;    

    return 0;
}

I compiled it using g++ test.cpp -std=c++11 -o test.

But the output was this:

Before Swapping using {}
a: 2 b: 10
After Swapping using {}
a: 10 b: 10
Before Swapping using make_pair()
a: 2 b: 10
After Swapping using make_pair()
a: 10 b: 2

So, my question is, since we can write {a, b} instead of writing std::make_pair(a, b) everytime (C++11 onwards), why are these two versions giving different output?

My guess was that the following line

std::tie(a, b) = {b, a};

is not making a pair and for some reason only mutating the value of a. But I am not sure.

Shubham
  • 2,847
  • 4
  • 24
  • 37
  • looks like undefined behavior... `a` is being set to the value of `b` and then the updated `a` is written to `b`... A sequence point problem. – Mikel F Jan 26 '17 at 21:27
  • @Jarod42 gives the answer below. You are right that you can construct a pair with {} but the compiler needs to know that that is what you are constructing, at that point. – Neil Gatenby Jan 27 '17 at 01:44

3 Answers3

13

tie(a, b) = {b, a};

will use std::tuple<int&, int&> operator = (std::tuple<int&, int&>&&). and not std::tuple<int&, int&> operator = (std::tuple<int, int>&&) as you expect.

std::tie(a, b) is a std::tuple<int&, int&>.
std::tuple has several operator =, but the only viable with (non typed) {a, b} are the copy/move assignment.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
5

{b, a} makes a std::tuple<int&, int&> while std::make_pair makes a std::pair<int, int>.

Consider what happens with std::pair<int&, int&>. It's essentially assigning one of the variables to the other, and then trying to assign the other to the first. It's equivalent to doing a = b; b = a; or b = a; a = b;.

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
3

just use make_tuple

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

it's the same thing a=b or b=a;

med amine
  • 33
  • 9