lambda
lambda는 C++11에서 새로운 개념이 추가되어서 나온것이 아닌 함수객체를 빠르게 만드는 문법이다. 주로 1회성 함수객체를 만들때 사용한다. 그렇다면 왜 이러한 람다식이 필요로 하는것인가?
람다의 필요성
enum class ItemType
{
None,
Armor,
Weapon,
Jewel,
}
enum class Rarity
{
Common,
Rare,
Unique,
};
class Item
{
public:
item(){}
item(int id,Rarity rare,ItemType type):_itemid(id),_rare(rare),_type(type)
public:
int _itemid=0;
Rarity _rare=Rarity::Common;
ItemType _type=ItemType::None;
};
이러한 데이터 구조를 가지고 있다고 가정하고, 아이템을 생성해보자.
int main()
{
vector<Item> v;
v.push_back(Item(1,Rarity::Common,ItemType::Weapon));
v.push_back(Item(2,Rarity::Rare,ItemType::Armor));
v.push_back(Item(3,Rarity::Unique,ItemType::Jewel));
}
아이템들은 특정 조건에 맞춰서 탐색/제어 해야 될 상황이 필요할 것이다.
{
struct IsUnique()
{
bool operator()(Item& item)
{
return item._rare==Rarity::Unique;
}
}
auto find = std::find_if(v.begin(),v.end(),IsUnique());
if(find!=v.end())cout<<find->_itemid;
}
이런 식으로 그때그때 상황에 맞는 Functor를 제작해야한다. 위 코드와 같이 아이템이 별로 없을 때는 무리가 없지만, 아이템이 많이 짐에 따라서 조건이 세분화 되고 다양해지게 된다면 Functor의 수 또한 매우 늘어나게 될것이다. 그런데 이렇게 Functor를 매번 생성해서 넣어주게 된다면 가독성 문제 및 코드 반복이 발생 할 수도 있다. 이것을 어느정도 방지하는 것이 람다식의 의의이다.
람다표현식
람다는 익명 함수이며 표현식은 [캡처](인자){구현부}로 되어있다.
auto IsUniqueLambda=[](Item& item){return item._rare==Rarity::Unique;}//클로저
//[]()->int{}와 같이 ()->자료형{} 형태를 취하게 되면 return 값을 정해줄수있다.
auto find = std::find_if(v.begin(),v.end(),IsUnique());
auto find = std::find_if(v.begin(),v.end(),IsUniqueLambda);
auto find = std::find_if(v.begin(),v.end(),[](Item& item){return item._rare==Rarity::Unique;});
//모두 같은 역할을 수행한다.
이 코드가 위에서 구현했던 Functor와 동일한 역할을 수행한다.이렇게 람다식에 의해 실행시점에서 만들어진 객체를 클로저라고 한다. 이러한 람다식은 Functor와 차별화된 기능이 하나 있다.
struct FindItemId()
{
FindItemId(int itemid):_itemid(itemid){}
bool operator()(Item& item)
{
return item._itemid==itemid;
}
int _itemid;
}
int itemid=3;
auto findLambda=[=](Item& item){return item._itemid==itemid}
//[]()->int{}와 같이 ()->자료형{} 형태를 취하게 되면 return 값을 정해줄수있다.
auto find = std::find_if(v.begin(),v.end(),FindItemId(itemid));
auto find = std::find_if(v.begin(),v.end(),[](Item& item){findLambda});
//동일한 기능을 수행한다.
Functor에서는 인자로 받아서 내부에 저장을 해야만 했지만, 람다에서는 캡처에 의해 외부의 인자를 가져다 사용할수 있다.
[](캡처)
함수 객체 내부에 변수를 저장하는 개념이다.
기본캡처모드
기본캡처모드에는 값/복사방식(=)과 참조방식(&)이 있다.
- 값방식(=)
auto findLambda=[=](Item& item){return item._itemid==itemid}
캡처를 비워두게 되면 기본적으로 값 방식으로 동작하게된다. 외부의 값을 받아 오는 역할을 수행한다.
- 참조방식(&)
auto findLambda=[&](Item& item){return item._itemid==itemid}
참조값을 저장하는 형태이며 원본을 참조하는 형태이기 때문에 기존의 참조형태랑 동일한 역할을 수행한다.
지정캡처모드
기본캡처모드에서는 값방식을 택하면 모든 인자가 값방식으로 되고,참조방식을 택하면 모든 인자가 참조 방식으로 되지만 지정 캡처모드에서는 각 인자의 방식을 지정할수 있으며 가독성과 같은 이유로 지정캡처모드를 권장한다.
FindItem(int itemid,Rarity rare,itemType item):_itemid(itemid),_rare(rare),_type(item)_{}
bool operator()(Item& item)
{
return item._itemid==itemid && ;item._rare==_rare && item._type==_type;
}
int _itemid;
Rarity _rare;
itemType _type;
예를 들어 이런식으로 찾아야될 조건이 늘어났다고 가정하고 itemid는 값방식, rare와 type은 참조방식으로 하고 싶다고 한다면, 다음과 같이 작성하는 것이 지정캡처모드이다.
auto findLambda=[itemid,&](Item& item)
{
return item._itemid==itemid && item._rare==_rare && item._type==_type;
}
auto findLambda=[=itemid,&rare,&type](Item& item)
{
return item._itemid==itemid && item._rare==_rare && item._type==_type;
}
//두 코드 모두 똑같다
'C++복습' 카테고리의 다른 글
C++복습) C++20/Concept (0) | 2022.01.10 |
---|---|
C++복습) Modern C++/smart pointer (0) | 2022.01.03 |
C++복습) Modern C++/전달 참조 (0) | 2021.12.30 |
C++복습) Modern C++/ 오른값 참조( rvalue)와 std::move (0) | 2021.12.29 |
C++복습) Modern C++/ override , final (0) | 2021.12.28 |
댓글