Fundamental of CS/: : C++

[Types] std::pair, tuple

Jay.P Morgan 2024. 7. 31. 20:35

 

C++ pair와 tuple

1. std::pair 개념

이번 시간에는 C++에서 자주 사용되는 pair와 tuple에 대해 알아봅니다.

먼저 두 개의 데이터를 하나로 묶어 관리할 수 있는 std::pair를 살펴보겠습니다.

std::pair는 C++ 표준 라이브러리에서 제공하는 타입으로, <utility> 헤더에 정의되어 있습니다.

구조는 매우 간단합니다.

template<class T1, class T2>
struct pair;

두 개의 서로 다른 타입을 저장할 수 있는 템플릿 구조체입니다.

 

 

2. std::pair 사용 방법

예를 들어 정수와 문자열을 하나로 묶어 관리할 수 있습니다.

std::pair<int, std::string> person;
person = {1, "Rocky"};

pair 내부 데이터는 다음과 같이 접근합니다.

  • first
    • 첫 번째 타입에 접근
  • second
    • 두 번째 타입에 접근

예:

std::cout << person.first;
std::cout << person.second;

출력:

1
Rocky

이처럼 std::pair를 사용하면 단순한 데이터를 묶기 위해 별도의 구조체를 만들 필요가 없어집니다.

 

 

3. 함수 반환값으로 pair 활용

pair는 특히 함수에서 두 개 이상의 값을 반환해야 할 때 많이 사용됩니다.

예를 들어 나눗셈 함수를 생각해 봅시다.

divide(A, B)

함수는 결과값을 반환해야 하지만, B == 0인 경우에는 정상적인 결과를 반환할 수 없습니다.

이때:

  • 첫 번째 값 → 계산 결과
  • 두 번째 값 → 에러 코드

형태로 반환할 수 있습니다.

예:

std::pair<int, int> divide(int a, int b)
{
    if(b == 0)
        return {-1, 1};

    return {a / b, 0};
}

여기서:

  • 첫 번째 값
    • 나눗셈 결과
  • 두 번째 값
    • 에러 상태

를 의미합니다.

실제 프로젝트에서는 두 번째 값을 단순한 int 대신 에러 코드를 표현하는 별도의 enum이나 클래스로 정의하는 것이 더 좋은 방법입니다.

 

 

4. std::make_pair 사용

pair를 생성할 때 std::make_pair()를 사용할 수도 있습니다.

예:

auto result = std::make_pair(10, 0);

C++에서는 타입 추론이 가능하기 때문에 직접 타입을 작성하지 않아도 됩니다.

 

 

5. std::tuple 개념

pair는 두 개의 값만 저장할 수 있다는 제한이 있습니다.

여러 개의 값을 하나로 묶고 싶다면 std::tuple을 사용할 수 있습니다.

tuple은 pair의 일반화된 형태라고 생각하면 됩니다.

예:

std::tuple<double, char, std::string> student;

하나의 객체 안에:

  • double
  • char
  • string

처럼 여러 타입을 함께 저장할 수 있습니다.

 

 

6. tuple 데이터 접근 방법

tuple의 데이터는 std::get<>()을 사용하여 접근합니다.

예:

std::cout << std::get<0>(student);
std::cout << std::get<1>(student);
std::cout << std::get<2>(student);

접근 방식:

  • get<0>()
    • 첫 번째 값
  • get<1>()
    • 두 번째 값
  • get<2>()
    • 세 번째 값

예:

auto student = std::make_tuple(
    3.8,
    'A',
    "Lisa Simpson"
);

출력:

3.8
A
Lisa Simpson

 

 

7. tuple 타입 선언 방법 개선

기존 방식에서는 타입을 직접 작성해야 합니다.

std::tuple<double, char, std::string> student;

하지만 C++에서는 타입 추론 기능을 활용할 수 있습니다.

std::make_tuple 사용

auto student = std::make_tuple(
    3.8,
    'A',
    "Lisa Simpson"
);

컴파일러가 자동으로 타입을 추론합니다.

 

 

8. C++17 구조적 바인딩(structured binding)

C++17부터는 더 편리한 방법이 추가되었습니다.

바로 구조적 바인딩입니다.

예:

auto [grade, level, name] = student;

이렇게 작성하면 tuple 내부 값을 변수처럼 바로 사용할 수 있습니다.

예:

std::cout << grade;
std::cout << level;
std::cout << name;

출력:

3.8
A
Lisa Simpson

기존처럼:

std::get<0>(student)
std::get<1>(student)
std::get<2>(student)

를 반복해서 작성할 필요가 없습니다.

 

 

9. pair, tuple, struct 사용 기준

pair와 tuple은 간단한 데이터 묶음을 표현할 때 매우 유용합니다.

하지만 항상 이것들이 정답은 아닙니다.

struct를 사용하는 것이 좋은 경우

  • 데이터 구조가 의미를 가지고 있을 때
  • 여러 곳에서 반복적으로 사용할 때
  • 변수 이름을 명확하게 표현해야 할 때

예:

struct Student
{
    double grade;
    char level;
    std::string name;
};

이런 경우에는 struct가 더 적합합니다.

 

 

pair / tuple이 좋은 경우

  • 특정 함수 내부에서만 사용하는 임시 데이터
  • 한 번만 사용하는 간단한 반환값
  • 별도의 타입 정의가 불필요한 경우

예:

return std::make_pair(value, error);

 

 

핵심 정리

  • std::pair
    • 두 개의 데이터를 묶는 타입
    • <utility> 헤더에 정의
    • first, second로 접근
  • std::tuple
    • 세 개 이상의 여러 타입을 묶을 수 있는 타입
    • std::get<>으로 접근
  • std::make_pair, std::make_tuple
    • 타입 추론을 이용해 간단하게 생성 가능
  • C++17 구조적 바인딩
    • auto [a, b, c] 형태로 tuple 데이터를 쉽게 분리 가능
  • 데이터 구조가 명확하고 재사용된다면 struct
  • 간단한 임시 데이터 묶음이라면 pair 또는 tuple

상황에 맞게 선택하는 것이 중요합니다.