//1)
struct Comparer
{
bool operator()(float a, float b)
{
return (a > b);
}
}
std::sort(scores.begin(), scores.end(), comparer);
//2)
bool Sort(float a, float b)// 남에게 공유하지 않을 코드라면 안 보이게 하는 것이 좋다.
{
return (a > b);
}
std::sort(scores.begin(), scores.end(), Sort);
// 위와 같은 코드는 유지보수 하기 힘듬, Sort 내용이 바뀌면....
// 람다식 이용
std::sort(scores.begin(), scores.end(), [](float a, float b){return (a > b)})
[<captures>](<parameters>) <specifiers> -> <return_type>
{
<body>
}
<captures> : 캡처 블록
<parameters> : 매개변수 목록(선택 사항)
<specifiers> : 지정자 (선택 사항)
<return_type> : 반환 형(선택 사항)
람다식을 품는 범위(scope)안에 있는 변수를 람다 식에 넘겨줄때 사용
쓸데 없이 중복해서 캡처하면 컴파일 에러
int w = 1;
int x = 10;
int y = 11;
int z = 12;
auto magic = [=, z]() // Error, z는 = 때문에 필요 없다.
{
return w + x + y + z;
};
Ex)
1)
auto noCapture = [](){std::cout << "No capturing" << std::endl;}
noCapture();
// noCapture를 다른 곳으로 넘길 수 있어서 의미 있음.
2) 바로 실행
[] {std::cout << "No capturing" << std::endl;}();
// 그다지 의미 없음, 이건 람다 안 쓰더라도 수행 할 수 있음
Ex) 외부 변수 사용하기
float score1 = 80.f;
float score2 = 20.f;
auto max = [](){return score1 > score2 ? score1 : score2;};
// 컴파일 에러 발생, 캡처를 아무것도 안 했으니까...
std::cout << "Max Value is " << max() << std::endl;
// 위 컴파일 에러 해결하기 위해 값에 의한 캡처 수행 하면 됨
auto max = [=](){return score1 > score2 ? score1 : score2;};
// 위에 있는 모든 변수를 값에 의한 캡처를 하여라
Ex) 값에 의한 캡처의 한계
float score1 = 80.f;
float score2 = 20.f;
auto changeValue = [=]()
{
score1 = 100.f;
// 컴파일 에러 발생, score1을 수정 할 수 없음,
// 값 복사를 해서 캡처한 것이니까...
};
changeValue();
Ex) 참조에 의한 캡처
float score1 = 80.f;
float score2 = 20.f;
// "왠지 여기를 보면 이 코드가 실행 되는것 같아서 혼란... 람다를 남발하면 가독성에 안좋다"
auto changeValue = [&]()
{
score1 = 100.f;// 참조에 의한 캡처라 값을 수정할 수 있고 컴파일 할 수 있음.
score2 = 100.f;
};
// "이런 캡처 방식은 코드의 가독성에 별로 좋지 않다, changeValue에서 무었을 하는지 확인 하기 위해 코드를 역행해서 봐야 한다."
changeValue();
Ex) 특정 변수만 캡처
float score1 = 80.f;
float score2 = 20.f;
1)
auto changeValue = [score1]()// score1만 값 캡처
{
// 컴파일 에러, score2에 접근 할 수 없음
std::cout << score1 <<" / " << score2 << std::endl;
};
changeValue();
2)
// score1, score2 이렇게 2개를 캡처 할 수 있음
auto changeValue = [score1, score2]()
{
std::cout << score1 <<" / " << score2 << std::endl;
};
changeValue();
Ex) 참조에 의한 특정 변수만 캡처
float score1 = 80.f;
float score2 = 20.f;
auto changeValue = [&score1]()// score1만 값 캡처
{
score1 = 100.f;
// score2는 접근 불가능...
};
changeValue();
Ex) 캡처 옵션 섞기
float score1 = 80.f;
float score2 = 20.f;
// 모든 값을 값 캡처하되 score1만 참조 캡처를 한다.
auto changeValue = [=, &score1]()
{
score1 = 100.f;
std::cout << score2 << std::endl;
};
changeValue();
auto message = [] {std::cout << "Let's go" << std::endl;};
Ex)
int score1 = 70;
int score2 = 85;
auto add = [](int a, int b) // 매개 변수
{
return a + b;
}
std::cout << add(score1, score2) << std::endl;
Ex) 정렬 하기
std::vector<float> scores;
scores.push_back(50.f);
scores.push_back(88.f);
scores.push_back(70.f);
std::sort(scores.begin(), scores.end(), [](float a, float b){return (a > b;)});
std::sort(scores.begin(), scores.end(), [](float a, float b){return (a <= b;)});
// 1)
int value = 100;
auto foo = [value]()
{
std::cout << ++value << std::endl;// 컴파일 에러
}
foo();
// 2)
int value = 100;
auto foo = [value]() mutable
{
std::cout << ++value << std::endl;// 에러는 발생 안 하지만 원본이 바뀌지는 않는다.
}
foo();
struct S { void f(int i); };
void S::f(int i) {
[&, i]{}; // OK
[&, &i]{}; // ERROR: i preceded by & when & is the default
[=, this]{}; // ERROR: this when = is the default
[=, *this]{ }; // OK: captures this by value. See below.
[i, i]{}; // ERROR: i repeated
}
class Temp
{
public:
Temp(int ii) : i{ ii } { }
int GetNumber() const
{
auto getNumber = [this] { return i; };
return getNumber();
}
private:
int i;
};
template <typename... Arg>
void Algorithm(int i, Arg... v)
{
auto helper = [&i, &v...] { return i * (h1(v...) + h2(v...)); };
// do something
}
-
auto lambda = [](int x, int y) { return x + y; };
int (*p)(int, int) = lambda;
std::function<int(int, int)> fp = lambda;
auto max = [](float a, float b){return a > b ? a : b;};
- 재사용이 필요할 때 람다를 함수로 바꾸면 되는 것 아닌가???
- 좋은 말이지만 현실적으로는 불가능. 다른 사람이 내가 만든 람다를 1000줄 라인에서 찾기 힘들다.
- IDE의 도움으로도 어떤 람다가 있는지 확인하기 힘들다. 함수 이름이 없어서 문자열 검색 힘듬.
- 함수가 아니기에 함수 내역으로도 안 떠짐.
make_unique, make_shared
생각보다 별로 쓸 곳은 없음
가변 인자...
다양한 매개변수 개수와 자료형을 지원하는 클래스 또는 함수 템플릿
매개변수 목록에서 생략 부호(...)를 씀.
가변 인자 템플릿 클래스
template<typename ... Arguments>
clas <클래스 명>
{
};
<typename ... Arguments>
// 템플릿 매개변수 꾸러미
template <typename... Argements>
<반환형> <함수명>(Arguments... args)
{
}
Ex) 가변 인자 템플릿 사용 예
// std::make_unique()
std::unique_ptr<Cat> myCat = std::make_unique<Cat>("Lulu", 2);// 다양한 인자
std::unique_ptr<Cat> myCat = std::make_unique<Vec2>(10.f, 15.f);// 다양한 인자
std::unique_ptr<Cat> myCat = std::make_unique<Cat>(20.f, 1.f, 0.f);// 다양한 인자
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
// std::shared_ptr
template<typename T, typename... Args>
std::shared_ptr<T> make_shared(Args&&... args)
{
RefCountObject<T> *ref = new RefCountObject<T>(std::forward<Args>(args)...);
std::shared_ptr<T> returnVal = returnVal.set(ref);
return returnVal;
}
가변 인자 템플릿 활용
Ex)
class Foo
{
public:
Foo() = delete;
Foo(float f1);
Foo(float f1, float f2);
~Foo() = default;
};
template<typename T, typename... TArgs>
T* Create(TArgs... args)
{
cout << "Creating instance" << endl;
T* object = new T(args...);
return object;
}
Foo* foo1 = Create<Foo>(1.0f);
Foo* foo2 = Create<Foo>(1.0f, 2.0f);
// Foo에 인자 3개받는 생성자 없어서 Error
Foo* foo2 = Create<Foo>(1.0f, 2.0f, 3.0f);