c++c++17g++c++20

Structure bindings not expected to compile in C++17, but it does anyway


I am reading here and there about structure bindings in C++20 specifically. This feature was however introduced in C++17 and it had few problems:

  1. Cannot use storage specifiers (static or thread_local)
  2. When used within a class if the data members are private then structure bindings used in methods or friend functions should not work.

To test that, I wrote this code:

#include <string>

struct Point {
  int x, y;
};

class AClass {
 private:
  std::string mString;
  int mId;

 public:
  void aMethod(const AClass& p) { 
    auto s = p.mString;
    auto [str, id] = p;  // this should not work, because we're
                         // accessing private memebers
  }
  friend void aFriendFunction(const AClass& p) {  
    auto s = p.mString;
    auto [str, id] = p; // Likewise as aMethod
  }
};

int main() {
  Point p{3, 5};

  // This shouldn't work in C++17
  static auto [u, v] = p;  // This gives a warning, compilation depends

  return 0;
}

Which, from what I gathered, should not work. And I assumed by "not working" it should not compile. However, this line:

g++ main.cpp -o out -std=c++17

Gives me an output which seems valid and without issues. So why is this working? Am I missing something?

I am also noticing that in gcc 7.1. this actually gives the expected error (using an online compiler). But when switching to my version of gcc (13.3.0) I get the aforementioned warning. This raises for me the question of how structured binding changed within the same C++ version.


Solution

  • While the C++ standard is published anew once every three years since 2011, it's possible for the committee to identify language defects and apply fixes retroactively to already published standard revisions (even C++14 saw updates years later). This won't affect old compilers, but as compilers get updated they may implement the fixes and you'll see behavior changes even for the same C++ standard switch.

    The cppreference page for structured bindings lists the issues you explored in your post, and links to the CWG issues/proposal to rectify them. Specifically

    1. P1091R3 - Extending structured bindings to be more like variable declarations. This one allowed us to add storage class specifiers, and some other fixes.
    2. P0969R0 - Allow structured bindings to accessible members. This one changes the requirement on members from being public, to being accessible at the point of the structured binding declaration.

    Both of these papers were applied retroactively as Defect Reports onto C++17 (if cppreference is to be believed). That's why GCC 13.3.0 is accepting the "problematic code" but GCC 7.1 does not. The defects weren't addressed and ratified at the time of GCC 7.1's release (2017, and the paper trail is from 2018).