C++ auto란?

What is auto?

Posted by dydtjr1128 on June 04, 2019 · 9 mins read CPP
auto?

1. Intro

C++ 표준에 기록되어 있는 auto라는 키워드는 원래 의미와 수정된 의미가 정의되어 있다. C++11전에는 auto는 자동 저장소 클래스에 있는 변수, 지역변수를 선언하는 역할을 했었다. 그러나 C++11부터 auto라는 키워드는 선언의 초기화 식에서 형식이 추론되는 변수를 선언하는 역할을 하고 있다. 이러한 차이 때문에 C++버전에 따라 auto라는 키워드는 다르게 동작 할 수 있다.

2. 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);

더욱 다양한 자료형을 사용하는 경우를 고려한다면 templeteauto를 같이 사용한다면 매우 깔끔하게 하나의 함수 작성만으로 끝나게 된다.

이러한 장점이 존재하는 auto가 있어 개발이 쉽고 간편해 지지만 무분별하게 사용하는것은 자료형을 파악하기 어려워 지고 가독성이 낮아지게 된다. 그렇기 때문에 코드 컨벤션 등을 지키면서 적절한 위치에 사용을 한다면 아름다운 코드를 만들 수 있을 것이다.

References

https://docs.microsoft.com/ko-kr/cpp/cpp/auto-cpp?view=vs-2019
https://m.blog.naver.com/kyed203/220068115571