17. auto / decltype / decltype(auto) 추론 규칙과 decltype((expr)) 괄호 함정
난이도 상내 리뷰 · C++
해설 · C++
해설 — auto / decltype / decltype(auto) 추론 규칙과 decltype((expr)) 괄호 함정
난이도: 상
요약
auto 는 템플릿 인자 추론과 같은 규칙으로 참조·cv 를 떨어뜨리고 값으로 추론한다. decltype(e) 는 e 의 선언 타입을 보존하되 괄호로 싸인 lvalue 표현식이면 참조가 된다. decltype(auto) 는 초기화식에 decltype 규칙을 그대로 적용해 참조/cv 를 보존한다.
예측 출력
w.v=77 a=99 b=10
is_ref a: 0
is_ref b: 0
is_ref c: 1
global=1000
핵심 개념 · 단계별
auto a = r;—r은int&지만auto는 참조를 벗겨int.a는w.v의 복사본.a=99는w.v에 무영향.decltype(w.v) b = w.v;—w.v는 멤버 접근(이름) → 선언 타입int.b는 복사본(10).decltype((w.v)) c = w.v;— 괄호((w.v))는 표현식이고w.v는 lvalue →decltype규칙상int&.c는w.v의 별칭.c=77이w.v를 77로 바꾼다.- 그래서
w.v=77(c로 변경),a=99(별개 복사본),b=10(변경 전 복사). is_reference: a→0(int), b→0(int), c→1(int&).decltype(auto) d = getRef();— 초기화식getRef()의 타입은int&→decltype(auto)가int&보존.d는global의 별칭.d=1000→global=1000.- 만약
auto d = getRef();였다면 참조가 벗겨져int복사본이 되어d=1000은global에 영향 없고 출력은global=42였을 것.
- 만약
흔한 오해·함정
decltype(x)vsdecltype((x)): 이름 그대로면 선언 타입, 괄호 한 겹이면 lvalue→참조. 이 차이가decltype(auto)반환 타입에서 버그를 만든다.- 제네릭 getter 의 댕글링/복사:
decltype(auto) get() { return obj.member; }는member의 선언 타입을 보존(보통 의도대로 참조 반환)하지만,return (obj.member);처럼 괄호를 붙이면 lvalue 참조로 추론돼, 지역 변수를 그렇게 반환하면 댕글링 참조가 된다. 반대로auto get()은 항상 복사라 큰 객체에서 불필요한 복사·성능 손실. - forwarding 과의 관계:
T&&(보편 참조,cpp_internals/problem8)는 인자 추론 규칙으로 lvalue/rvalue 를 구분하고,decltype(auto)는 그 값 카테고리를 반환 타입에 그대로 전달(완벽한 반환)할 때 짝으로 쓰인다 —decltype(auto) f(T&& x){ return std::forward<T>(x); }. 둘은 다른 메커니즘이지만 "값 카테고리 보존"이라는 목적에서 만난다.
면접 포인트
auto(값, 참조·cv 탈락) vsdecltype(선언 타입, 괄호 시 참조) vsdecltype(auto)(초기화식 decltype 보존)의 3분 비교.decltype((x))괄호 규칙이 제네릭 코드에서 복사 vs 참조, 나아가 댕글링을 가르는 실제 사례.- 반환 타입을
auto로 둘 때의 의도치 않은 복사와decltype(auto)/const auto&로 교정하는 법.