----------------
title : C++ 레퍼런스 - transform 함수
cat_title : transform
ref_title : transform, std::transform
path : /C++ Reference/algorithm
publish_date : 2019-04-19
----------------

##@ cpp-ref-start

#@ transform

`<algorithm>` 에 정의됨

```cpp-formatted
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_op` 이 `first1` 부터 `last1` 전까지 원소들을 인자로 전달하여 실행합니다.
2. 이항 함수 `binary_op` 이 `first1` 부터 `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)` 이 실행되는 셈입니다.
1. 어떠한 방식으로 실행 시킬지. 지정할 수 있습니다. `ExecutionPolicy` 참조.

### 인자들

* `first1, last1` `: transform` 을 적용할 원소들을 가리키는 범위
* `first2` : 두 번째 인자들의 시작
* `d_first` : 결과를 저장할 범위. `first1` 이나 `first2` 와 동일해도 된다.
* `policy` : 어떠한 방식으로 실행 시킬지. `ExecutionPolicy` 참조.
* `unary_op` : 원소들을 전달할 단항 함수. 해당 함수는 다음과 같이 생겨야 합니다.

```cpp-formatted
Ret unary(const Type &a);
```

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

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

```cpp-formatted
Ret binary(const Type1 &a, const Type2 &b);
```

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

### std::for_each 과의 관계

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

* `for_each` 의 경우 원소를 수정하지 않습니다. 물론 전달한 함수가 레퍼런스를 받는다면 수정할 수 있겟지만, 바람직한 사용 방식은 아닙니다. 또한 함수의 리턴값 역시 무시됩니다. 참고로 `for_each` 는 표준에 의해 원소들을 순서대로 접근함이 보장됩니다.
* `transform` 의 경우 원소를 수정하게 됩니다. 함수의 리턴값으로 해당 원소가 바뀝니다. 또한 `for_each` 와는 다르게, **순서대로 원소를 접근함이 보장되지 않습니다** (물론 범위 내에 원소를 모두 접근하기는 하지만, 꼭 처음부터 끝까지 순서대로 하는 것은 아니라는 의미입니다).

### 실행 예제

```cpp-formatted
// 아래 예제는 문자열을 대문자로 바꾸거나, 해당 아스키 값으로 바꿉니다.
#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;
  }
}
```

```exec
HELLO: 72 69 76 76 79
```

### 구현 예시

```cpp-formatted
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` : 범위 내에 원소들에 대해 함수를 실행시킵니다.