C++ 표준에 기록되어 있는 auto
라는 키워드는 원래 의미와 수정된 의미가 정의되어 있다. C++11전에는 auto는 자동 저장소 클래스에 있는 변수, 지역변수를 선언하는 역할을 했었다.
그러나 C++11부터 auto
라는 키워드는 선언의 초기화 식에서 형식이 추론되는 변수를 선언하는 역할을 하고 있다.
이러한 차이 때문에 C++버전에 따라 auto
라는 키워드는 다르게 동작 할 수 있다.
#include <iostream>
using namespace std;
int main( )
{
int count = 10;
int& countRef = count;
auto myAuto = countRef;
countRef = 11;
cout << count << " ";
myAuto = 12;
cout << count << endl;
}
위와 같은경우 count를 참조하는 변수를 받았으므로 11 12가 출력된다.
#include <initializer_list>
int main()
{
// std::initializer_list<int>
auto A = { 1, 2 };
// std::initializer_list<int>
auto B = { 3 };
// int
auto C{ 4 };
// C3535: cannot deduce type for 'auto' from initializer list'
auto D = { 5, 6.7 };
// C3518 in a direct-list-initialization context the type for 'auto'
// can only be deduced from a single initializer expression
auto E{ 8, 9 };
return 0;
}
D와 같이 식을 추론 할 수 없는경우나 E와 같은 여러변수를 넣어 초기화 하는 방법은 오류를 발생 시킨다.
#include <iostream>
using namespace std;
int plusNum(int i) {
return i + 1;
}
int main() {
auto a = true;
auto b = 'Y';
auto c = L'Y';
auto d = "문자열";
auto e = 26;
auto f = 3.12;
auto g = 10000000000;
auto &h = e;//참조
auto *i = &e;//포인터
cout << "값\t\t크기\t\t자료형" << endl;
cout << a << "\t\t" << sizeof(a) << "\t\t" << typeid(a).name() << endl;
cout << b << "\t\t" << sizeof(b) << "\t\t" << typeid(b).name() << endl;
cout << c << "\t\t" << sizeof(c) << "\t\t" << typeid(c).name() << endl;
cout << d << "\t\t" << sizeof(d) << "\t\t" << typeid(d).name() << endl;
cout << e << "\t\t" << sizeof(e) << "\t\t" << typeid(e).name() << endl;
cout << f << "\t\t" << sizeof(f) << "\t\t" << typeid(f).name() << endl;
cout << g << "\t" << sizeof(g) << "\t\t" << typeid(g).name() << endl;
auto j = plusNum;// 함수 포인터
cout << j(3) << endl;
auto printme = [] {cout << "hello" << endl; };// 매개변수 없는 함수, Lambda
printme();
auto plus2 = [](int i) {return i + 1; };//매개변수 있는 함수, Lambda
cout << plus2(3) << endl;
int count = 0;
auto k = [&](int i) {count += i; };//함수 자체(함수 내부에서 외부 변수 참조 시 & 대입), Lambda
auto l = [](int *i)->int& {return *i; };// 함수 자체(참조자를 리턴하려는 경우), Lambda
}
그러나 몇가지 경우에서는 auto를 사용할 수 없다.
auto
키워드는 함수의 매개변수로 쓰일 수 없다.
void add(auto a, auto b){}//X
struct {
auto b;
}
class Person{
auto name;
}
auto
키워드는 해당 객체의 자료형 크기를 정할 수 없기 때문에 구조체나 클래스 등의 맴버 변수로 쓰일 수 없다.
그러나 리턴형으로는 사용 가능하다.
auto A(){ //에러 후행 반환 형식을 지정하지 않음
return 3.2;
}
auto A()->double{ //정상, 함수 뒤에 후행 반환 형식 이라는 것을 지정해 주어야 한다.
return 3.2;
}
하지만 이런 식으로 후행 반환 형식을 지정한다는것은 일반적인 double return 형 함수와 똑같다.
그렇기 때문에 auto
는 templete와 함께 사용해야 의미가 있다.
template<typename T1, typename T2>
auto A(T1 t1, T2 t2)->decltype(t1+t2){
return t1+t2;
}
위의 A라는 함수에서 int형과 double형이 매개변수로 들어오면 decltype에서 t1, t2를 더해서 double이 되고, auto가 자동적으로 double형태로 리턴이 된다. 즉, decltype을 이용해서 리턴 시킬 자료형을 예측 가능하도록 만들어 줄 수 있다.
이러한 방법은 매우 큰 이점을 갖게 된다.
templete를 사용하는 상황에서는 int와 double형의 매개변수 대입 순서를 알 수 없다. 하지만 더 큰 자료형을 return을 시켜주고 싶을 때, decltype을 이용해서 double형을 리턴 시킬 수 있게 만들수 있다. 이때 auto
를 이용하여 자료형을 모르는 상황에서도 적절한 자료형인 double을 리턴 할 수 있게된다.
auto
를 사용하지 않는다면 사용자는 모든 경우의 자료형을 갖는 함수를 만들어야 할 것이다.
int A(int t1, int t2);
double A(int t1, double t2);
double A(double t1, int t2);
double A(double t1, double t2);
더욱 다양한 자료형을 사용하는 경우를 고려한다면 templete
과 auto
를 같이 사용한다면 매우 깔끔하게 하나의 함수 작성만으로 끝나게 된다.
이러한 장점이 존재하는 auto
가 있어 개발이 쉽고 간편해 지지만 무분별하게 사용하는것은 자료형을 파악하기 어려워 지고 가독성이 낮아지게 된다.
그렇기 때문에 코드 컨벤션 등을 지키면서 적절한 위치에 사용을 한다면 아름다운 코드를 만들 수 있을 것이다.
https://docs.microsoft.com/ko-kr/cpp/cpp/auto-cpp?view=vs-2019 https://m.blog.naver.com/kyed203/220068115571