#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

void goodbye(const string & s)
{
	cout << "Goodbye" << s << "\n";
}

class Object
{
public:
    void hello(const string & s)
    {
        cout << "Hello " << s << "\n";
    }
};

int main()
{
	// lambda-introducer
	// lambda-parameter-declaration
	// lambda-return-type-caluse
	// compound-statement
    // 익명 함수

	auto func = [](const int& i) -> void { cout << "Hello, World!"<< "\n"; };

	func(123);

    [](const int& i) -> void { cout << "Hello, World!"<< "\n"; } (1234); // 바로 실행
    
    {
        string name = "JackJack";
        [&]() {std::cout << name << "\n"; } (); // reference // 이 scope 안에 있는 변수들을 사용
        // [&name]() {std::cout << name << "\n"; } (); // reference
        // [=]() {std::cout << name << "\n"; } (); // copy
    }
    
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    
 	auto func2 = [](int val) {cout<<val<<"\n";};
    for_each(v.begin(), v.end(), func2); // algorithm 안에 정의.
    // for_each(v.begin(), v.end(), [](int val) {cout<<val<<"\n";}); // 보통 이렇게 사용.
    
    cout << []() -> int { return 1;}() << "\n";
    
    std::function<void(int)> func3 = func2;
    func3(123);
    
    std::function<void()>func4 = std::bind(func3, 456); // func3이 int를 받도록 되어있는데, func4는 파라미터가 없다. 하지만 bind로 456이 묶여있어서 아래와 같이 쓸 수 있다.
    func4();
    
    {
        Object instance;
        auto f = std::bind(&Object::hello, &instance, std::placeholders::_1);
        // Object의 hello function을 실행시키는데, instance가 필요하다.
        // 함수의 포인터, 인스턴스 포인터, hello의 파라미터가 1개이므로 placeholders로 1개 지정
        
        
        f(string("World"));
        
        auto f2 = std::bind(&goodbye, std::placeholders::_1);
        //그냥 함수
        
        f2(string("World"));
    }
    

	return 0;
}