2016. 7. 16. 19:01ㆍ프로그래밍/Effective Modern C++
decltype
주어진 이름이나 표현식의 형식을 알려준다.
C++11에서 decltype는 함수의 반환 형식이 그 매개변수 형식들에 의존하는 함수 템플릿을 선언할 때 주로 쓰인다.
너무 이해 안 되서 한 10번은 넘게 읽은 것 같다.
예시로 이해해보기
1 2 3 4 5 | std::deque<int> intDq; intDq.resize(10); authAndAccess(intDq, 5) = 10; std::cout << intDq.at(5) << std::endl;; | cs |
기본 적으론 해당 문장을 컴파일 하기 위해서이다.
authAndAccess 함수로부터 intDq의 원소의 레퍼런스를 받아 값을 바로 넣는 것이다.
template로 선언하면
1 2 3 4 5 6 7 8 9 10 11 | /* template<class Container, class Index> auto authAndAccess(Container& c, Index i) { // authenticateUser(); return c[i]; } // authAndAccess(intDq, 5) = 10; // error // 심각도 코드 설명 프로젝트 파일 줄 비표시 오류(Suppression) 상태 // 오류 C2106 '=': 왼쪽 피연산자는 l-value이어야 합니다. Test c:\users\jo minhyuk\documents\visual studio 2015\projects\test\test\test.cpp 39 */ | cs |
이런 꼬라지가 될 텐데. 실제로 컴파일을 해보면
return c[i] 에서 auto 연역을 통해 우측값이 변환되어 나오므로 정상적으로 컴파일이 되지 않는다.
실제로 l-value 관련 에러가 난다.
intDq[5]를 통해 int&를 돌려주나, authAndAccess에 대한
auto 반환 형식 연역 과정에서 참조가 제거되기 때문에 결국 반환 형태는 int가 된다.
그래서 decltype(auto) 라는 이상한 형태의 문법이 생겨나는데..
auto는 해당 형식이 연역되어야 하며, decltype는 그 연역 과정에서 decltype 형식 연역 규칙을 적용하겠다는 의미
위의 해결 코드의 문제점은 우측값을 전달할 수 없다는 것이다.
라고는 하는데 실제로 해보니 정상동작 하였다.
예시에 나온 팩토리 함수에서 리턴 받은 객체를 통해 접근하여 값을 복사했지만 정상동작....
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | std::deque<int> makeIntDque() { std::deque<int> dq; dq.resize(10); static int i = 1000; for (auto& value : dq) { value = i++; } return dq; } -- main auto copyFuncRtValue = authAndAccess(makeIntDque(), 5); std::cout << copyFuncRtValue << std::endl; | cs |
이상이 없었지만 책에서 제안하는 방법은
1 2 3 4 5 6 | template<class Container, class Index> decltype(auto) authAndAccess(Container&& c, Index i) { // authenticateUser(); return std::forward<Container>(c)[i]; } | cs |
좌측값 뿐만 아니라 우측값도 받아들일 수 있도록 선언을 고치는 것이다.
이를 보편 참조를 통해 좌측값과 우측값을 함께 관리하는 함수를 하나로 통합할 수 있다.
보편 참조에 std::forward를 붙인다.(오른 값에는 move, 보편 참조는 forward)
위는 C++14의 최종 버전이다. 아래는 C++11의 최종 버전.
1 2 3 4 5 6 | template<class Container, class Index> auto authAndAccess(Container&& c, Index i) -> decltype(std::forward<Container>(c)[i]) { // authenticateUser(); return std::forward<Container>(c)[i]; } | cs |
주의
1 2 3 4 5 6 7 8 9 10 11 12 13 | decltype(auto) f1() { int x = 0; ... return x; } decltype(auto) f2() { int x = 0; ... return (x); } | cs |
x 와 (x)는 decltype에서 전자는 int를 반환 후자는 int&를 반환한다.
지역 변수의 레퍼런스를 리턴하기때문에 망할 수 있다. 주의해야 한다.
기억해 둘 사항들
- decltype는 항상 변수나 표현식의 형식을 아무 수정 없이 보고한다.
- decltype는 형식이 T이고 이름이 아닌 좌측값 표현식에 대해서는 항상 T& 형식을 보고한다.(중요)
- c++14는 decltype(auto)를 지원한다. decltype(auto)는 auto처럼 초기치로부터 형식을 연역하지만,
그 형식 연역 과정에서 decltype의 규칙을 적용한다.
'프로그래밍 > Effective Modern C++' 카테고리의 다른 글
[effective modern c++] 항목 6 : auto가 원치 않은 형식으로 연역될 때에는 명시적 형식으로 초기화하자. (0) | 2016.09.10 |
---|---|
[effective modern c++] 항목 5 : 명시적 형식 선언보다는 auto를 선호하라 (0) | 2016.08.14 |
[effective modern c++] 항목 4: 연역된 형식을 파악하는 방법을 알아두자 (2) | 2016.07.16 |
[effective modern c++] 항목 2 : auto 연역 규칙 (0) | 2016.03.01 |
[effective modern C++] 항목 1 : 템플릿 형식 연역 규칙 숙지 (2) | 2016.03.01 |