3 분 소요

개요

기존의 tuple등은 내부 요소에 접근하는게 좀 까다로웠는데요(tuple 참고),

C++17 부터는 구조화된 바인딩을 이용하여 개체의 내부 요소나 멤버 변수에 쉽게 접근할 수 있게 해줍니다.

항목 내용
auto [변수 목록] 내부 요소의 복제본을 만들어 참조합니다. 수정시 복제본이 수정됩니다.
auto& [변수 목록] 내부 요소를 참조합니다. 내부 요소 수정이 가능합니다.
const auto& [변수 목록] 내부 요소를 참조합니다. 내부 요소 수정이 불가능합니다.
임시 개체인 경우 const auto&로 받으면 수명이 연장됩니다.(임시 개체 참고)
auto&& [변수 목록] 내부 요소를 전달 참조합니다.

다음과 같이 배열, tuple, 클래스등에 대해 적용할 수 있습니다.

배열

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int arr[]{1, 2, 3};

auto [a_17, b_17, c_17]{arr}; // auto [a_17, b_17, c_17] = arr; 과 동일
EXPECT_TRUE(a_17 == 1 && b_17 == 2 && c_17 == 3); // arr을 임시 개체에 복제하고, 복제본에 a_17 = temp[0], b_17 = temp[1], c_17 = temp[2] 바인딩

auto& [x_17, y_17, z_17]{arr};
EXPECT_TRUE(x_17 == 1 && y_17 == 2 && z_17 == 3); // x_17 = a[0], y_17 = a[1], z_17 = a[2] 에 바인딩

arr[0] = 10; // 원본 수정
arr[1] = 20;
arr[2] = 30;

EXPECT_TRUE(a_17 == 1 && b_17 == 2 && c_17 == 3); // 복제본이므로 원본 내용이 반영되지 않습니다.
EXPECT_TRUE(x_17 == 10 && y_17 == 20 && z_17 == 30); // 참조본이므로 원본 수정시 값이 동기화 됩니다.

tuple

1
2
3
4
5
6
7
8
9
10
11
12
auto data_11{std::make_tuple(10, "John")};

auto [id_17, name_17]{data_11}; // 복제본에 바인딩
EXPECT_TRUE(id_17 == 10 && name_17 == "John");

auto& [idRef_17, nameRef_17]{data_11}; // 원본에 바인딩
EXPECT_TRUE(idRef_17 == 10 && nameRef_17 == "John");

std::get<0>(data_11) = 20;

EXPECT_TRUE(id_17 == 10 && name_17 == "John");
EXPECT_TRUE(idRef_17 == 20 && nameRef_17 == "John");

클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class T {
public:
    int m_Id_11{10}; // C++11의 멤버 선언부 초기화
    std::string m_Name_11{"John"};    
};
T data_11;

auto [id_17, name_17]{data_11}; // 복제본에 바인딩
EXPECT_TRUE(id_17 == 10 && name_17 == "John");

auto& [idRef_17, nameRef_17]{data_11}; // 원본에 바인딩
EXPECT_TRUE(idRef_17 == 10 && nameRef_17 == "John");

data_11.m_Id_11 = 20;

EXPECT_TRUE(id_17 == 10 && name_17 == "John");
EXPECT_TRUE(idRef_17 == 20 && nameRef_17 == "John");

// 임시 개체의 수명 연장
const auto& [id_17, name_17]{
    T{30, "Sam"}  // 임시 개체를 생성했지만 const auto&로 받아 수명이 연장됩니다.
};
EXPECT_TRUE(id_17 == 30 && name_17 == "Sam");

컨테이너 활용

구조화된 바인딩컨테이너와 함께 사용하면 코드가 간결해 집니다.

레거시 C++ 스타일

insert() 로 데이터를 추가하고, iterator를 이용하며, pair로 삽입 실패를 검사합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 초기 데이터 입력
std::map<int, std::string> m;
m.insert(std::make_pair(0, "data0"));
m.insert(std::make_pair(1, "data1"));

// 요소 이터레이팅
std::map<int, std::string>::iterator itr = m.begin();
std::map<int, std::string>::iterator endItr = m.end();
for (; itr != endItr; ++itr) {
    std::cout << (*itr).first << (*itr).second << std::endl; // pair여서 first, second로 접근
}

// 삽입 실패 검사
std::pair<std::map<int, std::string>::iterator, bool> result = m.insert(std::make_pair(0, "data0"));
if (result.second != true) {
    std::cout << "insert fail" << std::endl;
} 

C++11 스타일

중괄호 초기화, 범위 기반 for(), auto 로 단순화 됐습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 초기 데이터 입력 - 중괄호 초기화로 단순화 됐습니다.
std::map<int, std::string> m_11{
    {0, "data0"}, 
    {1, "data1"}
}; 

// 요소 이터레이팅 - 범위 기반 for로 단순화 됐습니다.
for (const auto& item : m_11) {
    std::cout << item.first << item.second << std::endl; // pair여서 first, second로 접근
}

// 삽입 실패 검사 - auto 사용으로 단순화 됐습니다.
auto result{m_11.insert(std::make_pair(0, "data0"))};
if (result.second != true) {
    std::cout << "insert fail" << std::endl;
} 

C++17 스타일

초기식을 포함하는 if()구조화된 바인딩으로 단순화 되었고, 좀더 직관적입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 초기 데이터 입력 - 중괄호 초기화로 단순화 됐습니다.
std::map<int, std::string> m_11{
    {0, "data0"}, 
    {1, "data1"}
}; 

// 요소 이터레이팅 - 범위 기반 for와 구조화된 바인딩으로 단순화 됐습니다.
for (const auto& [key_17, value_17]: m_11) {
    std::cout << key_17 << value_17 << std::endl; 
}

// 삽입 실패 검사 -  초기식을 포함하는 if()와 구조화된 바인딩으로 단순화 됐습니다.
if (auto [itr_17, result_17]{m_11.insert(std::make_pair(0, "data0"))}; result_17 != true) {
    std::cout << "insert fail" << std::endl;
} 

태그:

카테고리:

업데이트:

댓글남기기