auto pi = 3.14; // pi는 double 타입으로 선언됨.
컴파일러는 3.14로부터 추론한 결과 pi를 double 타입으로 결정.
auto n = 3; // 3이 정수이므로 n을 int로 선언
const, 포인터 변수 선언 시의 '*'를 함께 사용할 수도 있다.
const auto ff = f; // <=> const float ff = f;
auto ptr = &n; // <=> int* ptr = &n;
auto* p = &n; // <=> int* p = &n;
참고로 포인터 변수의 값으로 지정할 수 없는 것은 에러가 발생한다.
auto* p = n; // n은 정수형 변수, 에러 발생
참조 변수의 선언에도 auto를 사용할 수 있다.
int n = 10;
int & ref = n; // ref는 int에 대한 참조 변수로 선언
auto ref2 = ref; // ref2는 int& 타입의 변수로 자동 선언
함수의 리턴 타입으로부터 추론하여 변수 타입 선언
int square(int x){ return x*x; }
auto ret = square(3); // 변수 ret은 int 타입으로 자동 선언
컴파일러는 square()의 리턴 타입이 int이므로 변수 ret의 타입을 int로 추론. square() 함수가 double을 리턴하는 함수로 수정되면 변수 ret의 타입도 double 타입으로 자동 결정됨.
이는 auto 키워드를 통해 수정에 따른 오류 가능성을 낮추는 효과가 있을 수 있음을 보여준다.
STL 템플릿에 활용
vector<int> v = {1, 2, 3, 4, 5};
iterator을 이용하여 벡터 v의 원소를 출력하려면 보통 다음 코드를 작성
for(auto it = v.begion(); it != v.end(); it++)
cout << *it << endl;
=> auto 키워드를 이용하여 간편화, 변수 it는 vector<int>::iterator 타입으로 추론됨.
기본 auto는 const와 &를 무시함
int num = 10;
int& ref = num;
const int con = num;
auto a1 = ref; // <=> int a1 = ref;
auto a2 = con; // <=> int a2 = con;
// auto로 참조 타입을 만들고 싶으면,
auto& a3 = ref;
// 또는
auto a4 = static_cast<int&>(ref);
C++11 부터 도입된 람다는 람다 대수(lambda calculis)에서 유래. 람다 대수에서 람다식(lambda expression)은 수학의 함수를 단순하게 표현하는 방법.
수학의 함수: f(x, y) = x + y
람다식: (x, y) -> x + y
위 식처럼 수학에서 이름없는 함수를 람다식이라고 부른다. 다음과 같이 괄호와 함께 x, y에 대입될 값을 지정하면 람다식의 계산이 이루어짐.
((x, y) -> x + y)(2, 3)
= 2 + 3
= 5
C++은 C++11 표준부터 이러한 람다식을 지원한다.
프로그래밍의 세계에서 람다는 이름 없느 익명 함수(anonymous function)으로, 람다식 혹은 람다 함수로 불림.
[](int x, int y){ cout << x + y; }; // 매개변수 x, y의 합을 출력하는 람다 작성
[](int x, int y) -> int { return x + y; }; // 매개변수 x, y 합을 리턴하는 람다 작성
[](int x, int y){ cout << x + y; }(2, 3); // x에 2, y에 3을 대입하여 코드 실행, 5 출력
표현 의미
[x] 변수 x의 값 활용
[=] 모든 변수의 값 활용
[&x] 참조 변수 x 활용
[&] 모든 참조 변수 활용
람다식의 형식은 컴파일러에만 알려져 있기에 개발자가 람다식을 저장하는 변수를 직접 선언할 수 없음. 개발자가 람다식을 저장하는 변수를 직접 선언할 수 없음. auto를 이용하면 람다식을 저장하는 변수를 쉽게 선언할 수 있음.
// auto로 람다식 다루기
#include <iostream>
#include <string>
using namespace std;
int main(){
auto love = [](strint a, string b){
cout << a << "보다 " << b << "가 좋아" << endl;
};
love("돈", "너"); // 람다식 호출
love("냉면", "만두"); // ""
람다식은 캡처 리스트를 이용하여 주변의 non-static 변수들(지역 변수나 멤버 변수)에 대해 값을 복사하여 받거나 참조를 활용할 수 있음. 아래 예제는 람다식이 캡처 리스트를 통해 외부 변수의 값을 전달받는 사례이다.
#include <iostream>
using namespace std;
int main(){
double pi = 3.14; // 지역 변수
auto calc = [pi](int r) -> double { return pi*r*r; };
cout << "면적은 " << calc(3);
}
다음 예제는 캡처 리스트를 통해 지역변수의 참조를 전달받고, 참조를 이용하여 지역변수를 변경하는 사례
#include <iostream>
using namespace std;
int main(){
int sum = 0; // 지역변수
[&sum](int x, int y){ sum = x + y; } (2, 3); // 합 5를 지역변수 sum에 저장.
cout << "합은 " << sum;
}
람다식은 STL 템플릿을 사용하여 프로그램을 작성할 때 더욱 유용. 아래 예제는 람다식 없이 STL 알고리즘을 활용하는 경우이다.
#include <iostream>
#include <vector>
#include <algorithm> // for_each() 함수
using namespace std;
void print(int n){
cout << n << " ";
}
int main(){
vector<int> v = {1, 2, 3, 4, 5};
for_each(v.begin(), v.end(), print);
}
람다식을 적용하여 전체 코드를 깔끔하게(print 함수는 for_each 함수에서만 사용됨)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
vector<int> v = {1, 2, 3, 4, 5};
for_each(v.begin(), v.end(), [](int n){ cout << n << " "; });
}
C++ 프로그램 작성 시 람다가 꼭 필요한 기능은 아님. 다만 간단하고 짧게 최적화된 코드를 작성하는데 도움이 됨. 특별히 람다가 유용한 경우는 다음과 같음.
장점: 간단한 함수를 빠르게 만들어 구현할 수 있습니다.
단점: 디버깅하기 힘들어질 수 있습니다.
(활용)
1. 한 번만 호출하고 재사용하지 않기 때문에 함수에 이름을 붙일 필요가 없는 경우
2. STL 알고리즘 함수의 매개변수에 연산 코드를 넘기는 경우, 연산 코드를 익명의 람다식으로 작성.