앞선 포스팅에서 람다 함수의 캡쳐(Capture) 기능에 대해 설명 했었습니다. (여기! 있습니다)
캡쳐 기능을 사용 하면 다음과 같이 활용 할 수 있습니다.
④ 템플릿을 대체하는 데 활용
람다 함수의 캡처 기능을 사용하면 람다 함수 몸체에서 외부 변수들을 마음껏 사용할 수 있을 뿐만 아니라 클로저(Closure)가 되어 함께 묶입니다. 이 기능을 활용하면 기존에 파라미터 타입과 개수 처리를 일반화하기 위해 사용하던 템플릿 사용을 지양할 수 있습니다. 아래 두 함수가 템플릿과 람다 함수를 이용해서 원하는 시점에 호출 되게 하려면 어떻게 하면 될까요?
void Function_Arg1(int arg1)
{
cout << "Function_Arg1 : " << arg1 << endl;
}
void Function_Arg2(int arg1, const char* arg2)
{
cout << "Function_Arg2 : " << arg1 << "," << arg2 << endl;
}
위 두 함수를 특정 파라미터와 묶어 특정 시점에 호출해서 사용하고 싶을 경우 템플릿을 이용하면 아래와 같은 방법으로 사용할 수 있습니다.
int arg1 = 1004;
const char* arg2 = "Lambda!";
vector<ITask*> taskList;
// 1. 컨테이너에 담는다.
taskList.push_back( new Task_1<void, int>(&Function_Arg1, arg1) );
taskList.push_back( new Task_2<void, int, const char*>(&Function_Arg2, arg1, arg2) );
…
// 2. 특정 시점에 컨테이너를 순회하며 실행시킨다.
for( auto i = taskList.begin(); i != taskList.end(); ++i )
{
(*i)->Do();
}
위와 같은 코드로 템플릿 객체를 사용하려면 다음과 같은 코드가 필요합니다.
template<typename RetType, typename ArgType1>
class Task_1 : public ITask
{
typedef function<RetType(ArgType1)> FunctionType;
public:
Task_1(FunctionType f, ArgType1 a1)
: function_(f), arg1_(a1)
{
}
virtual void Do()
{
cout << "Task_1::Do()" << endl;
function_(arg1_);
}
private:
FunctionType function_;
ArgType1 arg1_;
};
// 파라미터 2개짜리 함수를 담기 위한 템플릿 클래스
template<typename RetType, typename ArgType1, typename ArgType2>
class Task_2 : public ITask
{
typedef function<RetType(ArgType1,ArgType2)> FunctionType;
public:
Task_2(FunctionType f, ArgType1 a1, ArgType2 a2)
: function_(f), arg1_(a1), arg2_(a2)
{
}
virtual void Do()
{
cout << "Task_2::Do()" << endl;
…
…
실제 C++ 프로젝트를 진행하다 보면 위와 비슷한 형태의 템플릿 클래스를 자주 구현하게 됩니다. 이 때 발생하는 문제점은 함수의 파라미터가 늘어날 때마다 템플릿 클래스를 추가해 줘야 하고 코드가 직관적이지 않다는 점입니다. BOOST_PP를 이용하면 자동화할 수 있지만 디버깅이 굉장히 어렵고 작성자만 이해할 수 있는 코드가 만들어지곤 합니다. 때론 작성자도 이해 못하죠 ;)
그럼 이런 상황에서 람다 함수를 이용하면 어떨까요?
아래 예제를 보면 람다 함수의 캡처 기능을 이용해 깔끔하게 구현되는 것을 볼 수 있습니다. 뿐만 아니라 실행시킬 함수의 파라미터가 몇 개든 타입이 무엇이든 추가되는 코드는 없습니다. 앞으로 많은 부분에서 람다 함수를 이용해 템플릿 사용을 줄일 방안이 제안 되길 기대해 봅니다.
int arg1 = 1004;
const char* arg2 = "Lambda!";
...
...
typedef function<void(void)> LambdaType;
vector<LambdaType> lambdaList;
lambdaList.push_back( [=](){ Function_Arg1(arg1); } );
lambdaList.push_back( [=](){ Function_Arg2(arg1, arg2); } );
for_each( lambdaList.begin(), lambdaList.end(), [](LambdaType lambda)
{
lambda();
});
마치면서
4회에 걸쳐『Plus C++0x』람다(Lambda) 이야기를 했습니다. 막연히 람다(Lambda) 의 기능에 대해 설명 하기 보다는 이면에 깔린 배경 개념을 소개 함으로써 현대 프로그래밍 언어가 갖는 특징을 이야기 하고 싶었습니다.
다음 시리즈에서는 우측 값 참조(RValue Reference)에 대해 알아보고 C++0x에서 어떤 의미를 갖는지를 설명하려고 합니다. 람다(Lambda) 관련해서는 많은 내용을 한 번에 준비해서 쓰려니 고생스럽더군요. 이번엔 차근차근 포스팅 하면서 글을 완성할 수 있으면 좋겠네요 ;)
( 마이크로소프트웨어 6월호의 『생각의 직관적인 표현, 람다(Lambda)』를 보시면 보다 잘 정리 되고 추가 된 내용을 보실 수 있습니다. )
참고자료
1. MSDN - http://msdn.microsoft.com/en-us/library/dd293608.aspx
2. MSDN - http://msdn.microsoft.com/en-us/library/dd293599.aspx
3. MSDN - http://channel9.msdn.com/posts/kmcgrath/Lambda-Expressions-in-C/
4. MSDN - http://blogs.msdn.com/vcblog/archive/2008/11/18/stupid-lambda-tricks.aspx
5. Wikipedia - http://en.wikipedia.org/wiki/First-class_function
6. Wikipedia - http://en.wikipedia.org/wiki/Higher-order_function
7. VSTS 2010 Team Blog - http://vsts2010.net/category/Language%20Development/C++0x
'Engineering' 카테고리의 다른 글
[Plus C++0x] 람다(Lambda) 이야기 (3) (1) | 2010.05.30 |
---|---|
[Plus C++0x] 람다(Lambda) 이야기 (2) (0) | 2010.05.28 |
[Plus C++0x] 람다(Lambda) 이야기 (1) (0) | 2010.05.28 |
C++ 0x 람다(Lambda)에 대한 마이크로소프트웨어 원고 요약 (0) | 2010.05.23 |