pair<> 클래스

 

pair 는 c++98 에도 이미 제공되고 있었다.

pair 는 두 객체를 하나의 타입으로 묶어 사용한다.

예를들면, 2차원 평면 상에서 좌표를 표현하는 경우 다음과 같이 사용할 수 있다.

pair<intint> 2d_point;

또 map 계열의 클래스는 키와 값의 쌍으로 구성되는데 이때도 pair 를 사용한다.

각 타입은 template 으로 정의 되므로 다른 타입이 사용될 수 있다.

pair 를 선언을 하면 선언 시에 사용된 객체의 default constructor 가 불리며 int 와 같은 primitive 타입이라면 0 으로 초기화 된다.

 

pair 정의 코드

bits/stl_pair.h g++ (GCC) 4.8.2
/**
   *  @brief Struct holding two objects of arbitrary type.
   *
   *  @tparam _T1  Type of first object.
   *  @tparam _T2  Type of second object.
   */
  template<class _T1, class _T2>
    struct pair
    {
      typedef _T1 first_type;    /// @c first_type is the first bound type
      typedef _T2 second_type;   /// @c second_type is the second bound type
      _T1 first;                 /// @c first is a copy of the first object
      _T2 second;                /// @c second is a copy of the second object
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 265.  std::pair::pair() effects overly restrictive
      /** The default constructor creates @c first and @c second using their
       *  respective default constructors.  */
      _GLIBCXX_CONSTEXPR pair()
      : first(), second() { }
      /** Two objects may be passed to a @c pair constructor to be copied.  */
      _GLIBCXX_CONSTEXPR pair(const _T1& __a, const _T2& __b)
      : first(__a), second(__b) { }
      /** There is also a templated copy ctor for the @c pair class itself.  */
#if __cplusplus < 201103L
      template<class _U1, class _U2>
    pair(const pair<_U1, _U2>& __p)
    : first(__p.first), second(__p.second) { }
#else
      template<class _U1, class _U2, class typename
           enable_if<__and_<is_convertible<const _U1&, _T1>,
                is_convertible<const _U2&, _T2>>::value>::type>
    constexpr pair(const pair<_U1, _U2>& __p)
    : first(__p.first), second(__p.second) { }
      constexpr pair(const pair&) = default;
      constexpr pair(pair&&) = default;
 
 
      // DR 811.
      template<class _U1, class typename
           enable_if<is_convertible<_U1, _T1>::value>::type>
    constexpr pair(_U1&& __x, const _T2& __y)
    : first(std::forward<_U1>(__x)), second(__y) { }
      template<class _U2, class typename
           enable_if<is_convertible<_U2, _T2>::value>::type>
    constexpr pair(const _T1& __x, _U2&& __y)
    : first(__x), second(std::forward<_U2>(__y)) { }
      template<class _U1, class _U2, class typename
           enable_if<__and_<is_convertible<_U1, _T1>,
                is_convertible<_U2, _T2>>::value>::type>
    constexpr pair(_U1&& __x, _U2&& __y)
    : first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { }
      template<class _U1, class _U2, class typename
           enable_if<__and_<is_convertible<_U1, _T1>,
                is_convertible<_U2, _T2>>::value>::type>
    constexpr pair(pair<_U1, _U2>&& __p)
    : first(std::forward<_U1>(__p.first)),
      second(std::forward<_U2>(__p.second)) { }
      template<typename... _Args1, typename... _Args2>
        pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>);
      pair&
      operator=(const pair& __p)
      {
    first = __p.first;
    second = __p.second;
    return *this;
      }
 
 
      template<class _U1, class _U2>
    pair&
    operator=(const pair<_U1, _U2>& __p)
    {
      first = __p.first;
      second = __p.second;
      return *this;
    }
      template<class _U1, class _U2>
    pair&
    operator=(pair<_U1, _U2>&& __p)
    {
      first = std::forward<_U1>(__p.first);
      second = std::forward<_U2>(__p.second);
      return *this;
    }
      void
      swap(pair& __p)
      noexcept(noexcept(swap(first, __p.first))
           && noexcept(swap(second, __p.second)))
      {
    using std::swap;
    swap(first, __p.first);
    swap(second, __p.second);
      }
    private:
      template<typename... _Args1, std::size_t... _Indexes1,
               typename... _Args2, std::size_t... _Indexes2>
        pair(tuple<_Args1...>&, tuple<_Args2...>&,
             _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>);
#endif
    };

 

pair 는 c++11 에서 크게 확장된 것은 없지만 표준 확장에 따라 move constructor 가 제공되고 swap() 이 추가되었다.

그 외 사용법은 c++98 에 비해 크게 달라진 점은 없다.

멈버 변수인 first 와 second 가 public 으로 선언되어 있기 때문에 접근 제한 없이 사용할 수 있다.

 

pair 를 간단히 생성하기 위해서 make_pair() 라는 함수가 존재한다.

make_pair 는 객체 생성을 위해 따로 타입을 쓰지 않아도 된다.

make_pair
pair<intfloat> int_float(0, 0.0f);

위 코드 대신 아래와 같이 사용할 수 있다.

make_pair
auto int_float = make_pair(0, 0.0f);

 

 

make_pair 의 코드:

bits/stl_pair.h g++ (GCC) 4.8.2
   /**
   *  @brief A convenience wrapper for creating a pair from two objects.
   *  @param  __x  The first object.
   *  @param  __y  The second object.
   *  @return   A newly-constructed pair<> object of the appropriate type.
   *
   *  The standard requires that the objects be passed by reference-to-const,
   *  but LWG issue #181 says they should be passed by const value.  We follow
   *  the LWG by default.
   */
  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 181.  make_pair() unintended behavior
#if __cplusplus >= 201103L
  // NB: DR 706.
  template<class _T1, class _T2>
    constexpr pair<typename __decay_and_strip<_T1>::__type,
                   typename __decay_and_strip<_T2>::__type>
    make_pair(_T1&& __x, _T2&& __y)
    {
      typedef typename __decay_and_strip<_T1>::__type __ds_type1;
      typedef typename __decay_and_strip<_T2>::__type __ds_type2;
      typedef pair<__ds_type1, __ds_type2>        __pair_type;
      return __pair_type(std::forward<_T1>(__x), std::forward<_T2>(__y));
    }
#else
  template<class _T1, class _T2>
    inline pair<_T1, _T2>
    make_pair(_T1 __x, _T2 __y)
    return pair<_T1, _T2>(__x, __y); }
#endif

 

c++11 의 make_pair 는 rvalue 인자를 받으므로,

해당 타입이 move semantics 를 지원한다면 인자로 전달된 객체가 변경된다.

 

간단한 테스트 코드 :

example : make_pair
#include <iostream>
#include <vector>
#include <utility>
using namespace std;
 
void print(const vector<int> &v) {
    cout << "[ ";
    for (auto i : v) {
        cout << i << " ";
    }  
    cout << " ]" << endl;
}
 
int main() {
    vector<int> a;
    a.push_back(1);
    a.push_back(2);
 
    print(a);
    vector<int> b;
    b.push_back(10);
    b.push_back(20);
    print(b);
 
    auto c = make_pair(move(a), move(b)); // 이제 a 와 b 를 사용하지 않는다
    print(a);
    print(b);
    return 0;
}
출력 결과
[ 1 2  ]
[ 10 20  ]
[  ]
[  ]


: