Initializer list vs tuple with std::tie()

Revision en2, by drdilyor, 2023-05-29 10:12:02

Take a look at this innocent piece of code:

    vector<vector<int>> arr{
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12},
        {13, 14, 15, 16},
    };
    int n = arr.size();

    for (int i = 0; i < n/2; i++) {
        for (int j = 0; j < n/2; j++) {
            tie(arr[i][j], arr[j][n-i-1], arr[n-i-1][n-j-1], arr[n-j-1][i]) =
                {arr[j][n-i-1], arr[n-i-1][n-j-1], arr[n-j-1][i], arr[i][j]};
            //tie(arr[i][j], arr[j][n-i-1], arr[n-i-1][n-j-1], arr[n-j-1][i]) =
            //    tuple{arr[j][n-i-1], arr[n-i-1][n-j-1], arr[n-j-1][i], arr[i][j]};
        }
    }
    for (auto& i : arr) {
        for (int j : i) 
            cout << j << ' ';
        cout << '\n';
    }

Outputs (with optimizations disabled):

4 8 12 16 
3 7 11 15 
8 7 10 14 
4 3 9 13 

which is totally gibberish.

Using tuple{} instead of initializer list ({}) for tie() gives the correct answer. This behavior is observed both on GCC and clang.

In fact, this is present with code as simple as this:

int a = 1, b = 2;
tie(a, b) = {b, a};

This once again shows one of the dark sides of C++. Hope no one spends 30 mins searching for such bug after this blog :):

Tags c++

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en2 English drdilyor 2023-05-29 10:12:02 111
en1 English drdilyor 2023-05-29 10:09:34 1197 Initial revision (published)