[C++] 컨테이너 안에 클래스가 들어있을 때, 클래스 안의 멤버들을 순회하는 이터레이터를 반환받는 방법 + mem_fn
``cpp vector<cls>``가 있을 때, `` cls.value``들만 뽑아내고 싶은 경우가 빈번하게 있다.
일반적인 경우 그냥 반복문 돌면서 처리해주면 되지만,
라이브러리 등을 사용할 때는 반드시 `` cls.value``로 이루어진 iterator를 넘겨야만 하는 경우가 있다.
이런 경우 처음으로 드는 생각은 함수형의 ``cpp filter()``인데, 이는 copy가 발생하게 된다.
copy 없이 `` cls`` 내의 멤버인 `` cls.value``들만 순회하는 iterator는 다음과 같은 방식으로 만들 수 있다.
boost::transform_iterator
따라서 클래스 내의 멤버에 접근하는 람다를 넘겨주면, 다음과 같이 iterator를 반환받을 수 있다.
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';
}
```
따라서 다음과 같이 람다를 대체해서 사용할 수 있다.
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;
}
```
'Languages & Frameworks > C C++' 카테고리의 다른 글
[C++] thread는 context가 필요하다. (0) | 2018.09.11 |
---|---|
[C++] lambda (bind 보다는 lambda를 쓰자) (0) | 2018.09.03 |
[C/C++] strncpy()는 NULL문자를 넣어주지 않는다. (0) | 2018.08.21 |
[C++] \r이 포함된 문자열 출력할 때 이상하게 출력되는 현상 (0) | 2018.08.21 |
[C++] 맵 : unordered_map (hash_map) (2) | 2018.08.20 |