std::find_if(container.begin(), container.end(),
[](int val) { return 0 < val && val < 10; });
using FilterContainer =
std::vector<std::function<bool(int)>>; // 필터링 하는 "함수 객체"를 받는 컨테이너
FilterContainer filters; // 필터링 함수들
void addDivisorFilter() {
auto calc1 = computeSomeValue1();
auto calc2 = computeSomeValue2();
auto divisor = computeDivisor(calc1, calc2);
filters.emplace_back( // danger! ref to divisor will dangle
[&](int value) { return value % divisor == 0; }
);
}
filters.emplace_back(
[&divisor](int value) // default caputre 모드를 사용하지 않아도 여전히 같은 문제 발생
{ return value % divisor == 0; }
);
template<typename C>
void workWithContainer(const C& container)
{
auto calc1 = computeSomeValue1();
auto calc2 = computeSomeValue2();
auto divisor = computeDivisor(calc1, calc2);
using ContElemT = typename C::value_type;
using std::begin;
using std::end;
if (std::all_of(
begin(container), end(container), // 컨테이터의 모든 값이 divisor의 배수인가?
[&](const ContElemT& value)
{ return value % divisor == 0; })
) {
… // 그런 경우
} else {
… // 아닌 경우
}
filters.emplace_back(
[=](int value) { return value % divisor == 0; } // 더 이상 dangling 문제가 발생하지 않음
);
// Widget 클래스가 필터들의 컨테이너에 필터 함수를 추가하는 method 를 가지고 있다고 가정
class Widget { public:
… // 생성자 등등
void addFilter() const; // filter를 filters 에 추가
private:
int divisor; // Widget의 필터에 사용됨
}
void Widget::addFilter() const
{
filters.emplace_back(
[](int value) { return value % divisor == 0; } // 멤버 변수 Widget::divisor를 사용할 수 없음
);
void Widget::addFilter() const
{
filters.emplace_back(
[divisor](int value)
{ return value % divisor == 0; } // 지역 변수 divisor 가 없기 때문에 컴파일 되지 않음
);
}
void Widget::addFilter() const
{
filters.emplace_back(
[=](int value) { return value % divisor == 0; }
);
}
void Widget::addFilter() const
{
auto currentObjectPtr = this;
filters.emplace_back(
[currentObjectPtr](int value)
{ return value % currentObjectPtr->divisor == 0; }
);
}
// 이 람다로 만들어진 closure의 유효성이 해당 closure가 만들어진 시점에 capture된 Widget 객체의 수명에 의해 제한됨(this 때문)
using FilterContainer =
std::vector<std::function<bool(int)>>;
FilterContainer filters;
void doSomeWork()
{
auto pw =
std::make_unique<Widget>();
pw->addFilter(); // Widget::divisor를 사용하는 필터를 추가
…
} // Widget 이 제거 되고 filters 에 dangling pointer 가 발생
void Widget::addFilter() const {
auto divisorCopy = divisor; // copy data member
filters.emplace_back(
[divisorCopy](int value) // capture the copy
{ return value % divisorCopy == 0; } // use the copy
);
void Widget::addFilter() const
{ filters.emplace_back( // C++14:
[divisor = divisor](int value) // copy divisor to closure
{ return value % divisor == 0; } // use the copy
);
}
람다는 static 으로 선언된 객체를 "사용" 할수는 있지만 "capture" 할수는 없다.
// 아래예는 모든 내용을 값으로 "capture" 하고 람다 내에서 사용한다고 생각할 수 있지만 실제로는 전혀 그렇지 않다.
void addDivisorFilter()
{
static auto calc1 = computeSomeValue1(); // now static
static auto calc2 = computeSomeValue2(); // now static
static auto divisor = // now static
computeDivisor(calc1, calc2);
filters.emplace_back(
[=](int value) // 아무것도 capture 되지 않음
{ return value % divisor == 0; } // 그냥 위의 static divisor 를 가리킨다
);
++divisor; // divisor 를 수정
}