들어가며
이번 포스트에서는 C++14 부터 포함된 제네릭 람다 표현식에 대해 살펴 보도록 하겠다. 제네릭 람다 표현식은 auto 키워드를 이용해 하나의 람다 표현식 코드로 다양한 타입의 인자들에 대해 대응할 수 있는 람다 표현식을 말한다.
일반 람다 표현식 vs 제네릭 람다 표현식
먼저 일반적인 람다 표현식과 그 사용을 살펴 보자.
auto add = [](int a, int b) { return a + b; };
std::cout << add(1, 1) << std::endl;
std::cout << add(1.1, 1.2) << std::endl;
std::cout << add(1, 1.4) << std::endl;
C++에서 실수는 정수로 암묵적 캐스팅 되기 때문에 위 예제 코드를 컴파일하면 정상적으로 컴파일 된다. 하지만 1.1과 같은 실수가 모두 1로 다운 캐스팅 되었기 때문에 위 프로그램의 실행 결과는 모두 2다.
C++14 부터는 람다 표현식의 인자로 auto를 사용할 수 있게 변경 되었다. 아래 처럼 람다 표현식의 인자로 auto를 사용하게 되면 각 값에 맞는 타입으로 연산 되어 정확한 결과를 얻을 수 있다.
auto add = [](auto a, auto b) { return a + b; };
std::cout << add(1, 1) << std::endl; // 2
std::cout << add(1.1, 1.2) << std::endl; // 2.3
std::cout << add(1, 1.4) << std::endl; // 2.4
위와 같이 람다 표현식의 인자에 auto를 적용하여 다양한 타입에 대응하는 괄호 연산자 함수를 생성해 낼 수 있도록 하는것을 '제네릭 람다 표현식'이라고 한다.
위 코드가 컴파일러에 의해 함수자 클래스로 생성되는 것을 보면 괄호 연산자 오버로딩에 템플릿이 추가 되어 아래와 같은 형태의 코드가 생성된다.
class __lambda_5_16
{
public:
template<class type_parameter_0_0, class type_parameter_0_1>
inline /*constexpr */ auto operator()(type_parameter_0_0 a, type_parameter_0_1 b) const
{
return a + b;
}
template<>
inline /*constexpr */ int operator()<int, int>(int a, int b) const
{
return a + b;
}
template<>
inline /*constexpr */ double operator()<double, double>(double a, double b) const
{
return a + b;
}
template<>
inline /*constexpr */ double operator()<int, double>(int a, double b) const
{
return static_cast<double>(a) + b;
}
// ... 생략 ...
};
__lambda_5_16 add = __lambda_5_16{};
std::cout.operator<<(add.operator()(1, 1)).operator<<(std::endl);
std::cout.operator<<(add.operator()(1.1000000000000001, 1.2)).operator<<(std::endl);
std::cout.operator<<(add.operator()(1, 1.3999999999999999)).operator<<(std::endl);
(출저 : https://cppinsights.io/ 에서 코드 변환)
마치며
이상 C++14 부터 포함된 제네릭 람다 표현식에 대해 살펴 보았다. 핵심은 auto를 사용하는 경우 내부적으로 템플릿 함수로 변경 되며 각 타입별로 템플릿 인자가 지정된다는 것이다. 다음 포스트에서는 '템플릿 람다 표현식'에 대해 자세히 알아 보도록 하겠다.