엄범


``cpp vector<cls>``가 있을 때, `` cls.value``들만 뽑아내고 싶은 경우가 빈번하게 있다.

일반적인 경우 그냥 반복문 돌면서 처리해주면 되지만,

라이브러리 등을 사용할 때는 반드시 `` cls.value``로 이루어진 iterator를 넘겨야만 하는 경우가 있다.


이런 경우 처음으로 드는 생각은 함수형의 ``cpp filter()``인데, 이는 copy가 발생하게 된다.

copy 없이 `` cls`` 내의 멤버인 `` cls.value``들만 순회하는 iterator는 다음과 같은 방식으로 만들 수 있다.


boost::transform_iterator

내부적으로 정확히 어떻게 동작하는건지는 찾아보지 않았지만, 
첫 번째 인자로 지정된 iterable의 원소를 하나 씩 꺼내서 두 번째 인자로 지정된 function에 통과시킨 결과를 반환한다는 느낌이다.
```cpp
int main() {
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
const int N = sizeof(x) / sizeof(int);

typedef boost::transform_iterator<std::function<int(int)>, int*> doubling_iterator;
std::function<int(int)> doubling_lambda = [](int x) { return x * 2; };  // or just auto.
doubling_iterator i(x, doubling_lambda);
doubling_iterator i_end(x + N, doubling_lambda);

std::cout << "multiplying the array by 2:" << std::endl;
while (i != i_end)
std::cout << *i++ << " ";
std::cout << std::endl;
}
```


따라서 클래스 내의 멤버에 접근하는 람다를 넘겨주면, 다음과 같이 iterator를 반환받을 수 있다.

```cpp
void memberIterTest() {

vector<Foo> vec = { Foo(1), Foo(2), Foo(3), Foo(4) };


// 방법 1. 직접 선언해서 사용하는 방법

typedef boost::transform_iterator <std::function<int(Foo)>, vector<Foo>::iterator> cls_iter;

auto getData = [](Foo cls) { return cls.data; };

cls_iter i(vec.begin(), getData);

cls_iter i_end(vec.end(), getData);


// 방법2. make_transform_iterator를 사용하는 방법

auto getData = [](Foo cls) { return cls.data; };

auto i = boost::make_transform_iterator(vec.begin(), getData);

auto i_end = boost::make_transform_iterator(vec.end(), getData);

while (i != i_end)

std::cout << *i++ << " ";

std::cout << std::endl;

}

```

```

1 2 3 4

```


lambda를 사용할 수 없다면, std::mem_fn

``cpp std::mem_fn``은 클래스의 멤버를 가리키는 wrapper object를 반환하는 함수다.

메서드에 사용하면 함수 포인터를 반환하고, 멤버 변수에 사용하면 그 멤버 변수의 getter처럼 동작하는 함수 포인터를 반환한다.

```cpp

#include <iostream>

#include <functional>


class Foo {

public:

    int data = 7;

};


int main() {

    Foo f;

    auto getData = std::mem_fn(&Foo::data);

    std::cout << "data: " << getData(f) << '\n';

}

```


따라서 다음과 같이 람다를 대체해서 사용할 수 있다.

```cpp
void memberIterTest() {

vector<Foo> vec = { Foo(1), Foo(2), Foo(3), Foo(4) };


// 방법 1. 직접 선언해서 사용하는 방법

// mem_fn같은 경우 타입으로 decltype을 이용하는 것이 더 나아보인다. std::function<int(Foo)>를 사용하는 것 보다.

typedef boost::transform_iterator <decltype(std::mem_fn(&Foo::data)), vector<Foo>::iterator> cls_iter;

cls_iter i(vec.begin(), std::mem_fn(&Foo::data));

cls_iter i_end(vec.end(), std::mem_fn(&Foo::data));


// 방법 2. make_transform_iterator를 사용하는 방법

auto i = boost::make_transform_iterator(vec.begin(), std::mem_fn(&Foo::data));

auto i_end = boost::make_transform_iterator(vec.end(), std::mem_fn(&Foo::data));

while (i != i_end)

std::cout << *i++ << " ";

std::cout << std::endl;

}

```