KoreanFoodie's Study

Effective Modern C++ | 항목 33 : std::forward 를 통해 전달할 auto&& 매개변수에는 decltype 을 사용하라 본문

Tutorials/C++ : Advanced

Effective Modern C++ | 항목 33 : std::forward 를 통해 전달할 auto&& 매개변수에는 decltype 을 사용하라

GoldGiver 2022. 10. 26. 10:05

C++ 프로그래머의 필독서이자 바이블인, 스콧 마이어스의 Modern Effective C++ 를 읽고 기억할 내용을 요약하고 있습니다. 꼭 읽어보시길 추천드립니다!

항목 33 : std::forward 를 통해 전달할 auto&& 매개변수에는 decltype 을 사용하라

핵심 :

1. std::forward 를 통해 전달할 auto&& 매개변수에는 decltype 을 사용하라.

 

C+14 에서 가장 고무적인 기능은 일반적 람다(generic lambdas), 즉 매개 변수에 auto 를 사용하는 람다이다. 예시를 보자.

auto f = [](auto x) { return normalized(x); };

위 람다가 산출하는 클로저 클래스의 함수 호출 연산자는 다음과 같을 것이다.

class 컴파일러가_만든_이름 {
public:
  template<typename T>
  auto operator()(T x) const
  { return normalized(x); }
};

위의 람다는 normalized 에 항상 왼값(매개변수 x) 만을 전달한다. 그런데 만약 위의 람다가 왼값과 오른값을 다르게 처리한다면 위 코드를 어떻게 고쳐야 할까?

auto f = [](auto&& x) 
  { return normalized(std::forward<???>(x)); };

완벽 전달을 사용하면 될 것 같지만, 템플릿 형식으로 사용하는 T 가 없으므로, 위의 방식으로 수정할 수는 없다. 이 때, decltype 을 사용하면 문제를 해결할 수 있다(decltype 의 설명은 항목 28 참고).

auto f = [](auto&& x) 
  { return normalized(
    std::forward<decltype(x)>(x)); 
  };

decltype(x) 는 x 가 왼값이면 왼값 참조를, x 가 오른값이면 오른값 참조를 산출한다. 그런데 사실 x 가 오른값일 경우, decltype 은 오른값 참조가 아닌 비참조를 산출해야 한다. 하지만 항목 28 에 나온 std::forward 의 템플릿 형식 함수에 Widget 과 Widget&& 을 넣은 결과는 동일하므로, decltype(x) 는 오른값 참조 형식을 산출하게 된다.

임의의 매개변수들을 받아 완벽하게 전달하는 함수를 만드려면, 마침표 세 개만 추가하면 된다.

auto f = [](auto&&... xs) 
  { return normalized(
    std::forward<decltype(xs)>(xs)...); 
  };

 

Comments