모두의 코드
C++ 레퍼런스 - transform 함수

작성일 : 2019-04-19 이 글은 20904 번 읽혔습니다.

아직 C++ 에 친숙하지 않다면 씹어먹는 C++ 은 어때요?

transform

<algorithm> 에 정의됨

template <class InputIt, class OutputIt, class UnaryOperation>
OutputIt transform(InputIt first1, InputIt last1, OutputIt d_first,
                   UnaryOperation unary_op);  // (1)
template <class InputIt1, class InputIt2, class OutputIt, class BinaryOperation>
OutputIt transform(InputIt1 first1, InputIt1 last1, InputIt2 first2,
                   OutputIt d_first, BinaryOperation binary_op);  // (2)
template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
          class ForwardIt3, class BinaryOperation>
ForwardIt3 transform(ExecutionPolicy&& policy, ForwardIt1 first1,
                     ForwardIt1 last1, ForwardIt2 first2, ForwardIt3 d_first,
                     BinaryOperation binary_op);  // (3)

std::transform 은 범위 내 (first 부터 last 전 까지) 원소들 각각에 대해 인자로 전달한 함수를 실행 한 후, 그 결과를 d_first 에서 부터 쭉 기록한다.

  1. 단항 함수 unary_opfirst1 부터 last1 전까지 원소들을 인자로 전달하여 실행합니다.

  2. 이항 함수 binary_opfirst1 부터 last1 전까지 원소들과 first2 부터의 원소들을 쌍으로 전달해서 실행합니다. 예를 들어서 first1 부터 last1 이 {1,2,3} 이고 first2 부터의 원소가 {4,5,6} 이면 binary_op 에는 bianry_op(1,4), binary_op(2,5), binary_op(3,6) 이 실행되는 셈입니다.

  3. 어떠한 방식으로 실행 시킬지. 지정할 수 있습니다. ExecutionPolicy 참조.

인자들

  • first1, last1 : transform 을 적용할 원소들을 가리키는 범위

  • first2 : 두 번째 인자들의 시작

  • d_first : 결과를 저장할 범위. first1 이나 first2 와 동일해도 된다.

  • policy : 어떠한 방식으로 실행 시킬지. ExecutionPolicy 참조.

  • unary_op : 원소들을 전달할 단항 함수. 해당 함수는 다음과 같이 생겨야 합니다.

Ret unary(const Type &a);

참고로 함수의 인자로 굳이 const& 일 필요는 없습니다. TypeInputIt 의 역참조된 타입과 같거나 Type 로 변환될 수 있어야 하며, Ret 의 경우 OutputIt 의 역참조 된 타입이거나, Ret 에 변환되서 대입할 수 있어야 합니다.

  • binary_op : 원소를 두 개 받는 이항 함수로 해당 함수는 아래와 같이 생겼습니다.

Ret binary(const Type1 &a, const Type2 &b);

함수의 인자로 굳이 const& 가 아니여도 됩니다. 위의 경우와 비슷하게 InputIt1InputIt2 의 역참조 타입이 Type1Type2 와 각각 같거나 해당으로 변환될 수 있어야만 합니다.

std::for_each 과의 관계

참고로 for_each 함수도 transform 함수와 하는 일은 거의 동일합니다. for_each 함수 역시, 범위 내에 원소들에 대해 전달된 함수를 호출하게 됩니다. 다만, 두 함수가 하는 역할은 조금 다른데

  • for_each 의 경우 원소를 수정하지 않습니다. 물론 전달한 함수가 레퍼런스를 받는다면 수정할 수 있겟지만, 바람직한 사용 방식은 아닙니다. 또한 함수의 리턴값 역시 무시됩니다. 참고로 for_each 는 표준에 의해 원소들을 순서대로 접근함이 보장됩니다.

  • transform 의 경우 원소를 수정하게 됩니다. 함수의 리턴값으로 해당 원소가 바뀝니다. 또한 for_each 와는 다르게, 순서대로 원소를 접근함이 보장되지 않습니다 (물론 범위 내에 원소를 모두 접근하기는 하지만, 꼭 처음부터 끝까지 순서대로 하는 것은 아니라는 의미입니다).

실행 예제

// 아래 예제는 문자열을 대문자로 바꾸거나, 해당 아스키 값으로 바꿉니다.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
#include <vector>

int main() {
  std::string s("hello");
  std::transform(
    s.begin(), s.end(), s.begin(),
    [](unsigned char c) -> unsigned char { return std::toupper(c); });

  std::vector<std::size_t> ordinals;
  std::transform(s.begin(), s.end(), std::back_inserter(ordinals),
                 [](unsigned char c) -> std::size_t { return c; });

  std::cout << s << ':';
  for (auto ord : ordinals) {
    std::cout << ' ' << ord;
  }
}

실행 결과

HELLO: 72 69 76 76 79

구현 예시

template <class InputIt, class OutputIt, class UnaryOperation>
OutputIt transform(InputIt first1, InputIt last1, OutputIt d_first,
                   UnaryOperation unary_op) {
  while (first1 != last1) {
    *d_first++ = unary_op(*first1++);
  }
  return d_first;
}

template <class InputIt1, class InputIt2, class OutputIt, class BinaryOperation>
OutputIt transform(InputIt1 first1, InputIt1 last1, InputIt2 first2,
                   OutputIt d_first, BinaryOperation binary_op) {
  while (first1 != last1) {
    *d_first++ = binary_op(*first1++, *first2++);
  }
  return d_first;
}

참고 자료

for_each : 범위 내에 원소들에 대해 함수를 실행시킵니다.

첫 댓글을 달아주세요!
프로필 사진 없음
강좌에 관련 없이 궁금한 내용은 여기를 사용해주세요

    댓글을 불러오는 중입니다..