Giới thiệu Structured Binding trong C++17

Structured Binding Declaration là một tính năng mới trong C++17, cho phép bạn khai báo nhiều biến cùng lúc và gán chúng với các thành phần của một đối tượng. Cú pháp sử dụng từ khóa auto kết hợp với cặp ngoặc vuông [].

Cú pháp cơ bản:

cv-auto+ref [var1, var2, ..., varN] = init_expr;
cv-auto+ref [var1, var2, ..., varN] (init_expr);
cv-auto+ref [var1, var2, ..., varN] {init_expr};
// cv-auto+ref bao gồm: auto, auto const, auto &, auto&&, v.v.

Có hai dạng biến trong structured binding:

  • Biến không tham chiếu: Đối tượng khởi tạo được sao chép, và biến sẽ ràng buộc với các thành phần của bản sao đó.
  • Biến tham chiếu: Không sao chép đối tượng, biến ràng buộc trực tiếp với các thành phần của đối tượng gốc.

Biểu thức khởi tạo có thể thuộc một trong ba loại sau:

  • Mảng: Biến ràng buộc với từng phần tử của mảng.
  • Kiểu hỗ trợ tuple_size (như pair, tuple): Biến ràng buộc với kết quả của get<i>(e).
  • Struct có thành viên public: Biến ràng buộc với các thành viên public của struct.

Ví dụ mã nguồn C++17

#include <iostream>
#include <utility>
#include <set>
#include <map>
using namespace std;

struct S {
    int a, b, c;
};

map<string, int> get_map() {
    return {
        {"hello", 1},
        {"world", 2},
        {"it's",  3},
        {"me",    4}
    };
}

int main() {
    // Gán từ pair
    auto [x, y] = pair(2, "3"s);
    cout << x << y << endl; // Output: 23

    // Gán từ kết quả insert set
    set<string> my_set;
    if (auto [it, ok] = my_set.insert("Hello"); ok) {
        cout << *it << endl; // Output: Hello
    }

    // Gán từ mảng
    int data[] = {1, 2, 3, 4};
    const auto& [a1, a2, a3, a4] = data;
    cout << a1 << a2 << a3 << a4 << endl; // Output: 1234

    // Gán từ struct
    S obj = {4, 5, 6};
    auto& [p, q, r] = obj;
    p = 0; q = 1; r = 2;
    cout << obj.a << obj.b << obj.c << endl; // Output: 012

    // Gán trong vòng lặp for
    for (auto&& [key, val] : get_map()) {
        cout << "key=" << key << " val=" << val << endl;
    }
    // Output:
    // key=hello val=1
    // key=it's val=3
    // key=me val=4
    // key=world val=2
}

Phân tích chi tiết

  • Dòng 20: Khai báo biến x (int) và y (string) từ pair. x nhận first, y nhận second.
  • Dòng 24: it là iterator, ok là bool từ kết quả insert của set.
  • Dòng 28: a1 đến a4const int& tương ứng 4 phần tử mảng.
  • Dòng 32: p, q, rint& ràng buộc với các thành viên a, b, c của struct.
  • Dòng 37: keystring&&valint& từ pair trong map.

Mã tương đương C++14

#include <iostream>
#include <utility>
#include <set>
#include <map>
using namespace std;

struct S {
    int a, b, c;
};

map<string, int> get_map() {
    return {
        {"hello", 1},
        {"world", 2},
        {"it's",  3},
        {"me",    4}
    };
}

int main() {
    auto kv = make_pair(2, "3"s);
    auto& x = kv.first; auto& y = kv.second;
    cout << x << y << endl;

    set<string> my_set;
    set<string>::iterator it;
    bool ok;
    tie(it, ok) = my_set.insert("Hello");
    if (ok) cout << *it << endl;

    int data[] = {1, 2, 3, 4};
    const auto& a1 = data[0], &a2 = data[1], &a3 = data[2], &a4 = data[3];
    cout << a1 << a2 << a3 << a4 << endl;

    S obj = {4, 5, 6};
    auto& p = obj.a, &q = obj.b, &r = obj.c;
    p = 0; q = 1; r = 2;
    cout << obj.a << obj.b << obj.c << endl;

    for (auto&& kv : get_map()) {
        auto&& key = forward<decltype(kv.first)>(kv.first);
        auto&& val = forward<decltype(kv.second)>(kv.second);
        cout << "key=" << key << " val=" << val << endl;
    }
}

Thẻ: C++17 structured binding auto tuples pair

Đăng vào ngày 26 tháng 6 lúc 07:53