완벽한 전달

완벽한 전달





완벽한 전달이란 무엇을 의미합니까?

"포워딩"은 하나의 기능이 다른 기능으로 매개변수를 전달하는 프로세스입니다.
완벽할 때 함수는 전달을 수행하는 함수에서 전달된 동일한 개체를 받아야 합니다.

즉, 완벽한 전달이란 객체를 전달하는 것뿐만 아니라 lvalue 또는 rvalue, const 또는 volatile인지 여부에 관계없이 중요한 속성도 전달한다는 의미입니다.

정의에 대해 너무 걱정하지 마세요. 몇 가지 간단한 예를 살펴보겠습니다.

아래와 같은 간단한 클래스가 있다고 가정해 보겠습니다.

class Object {
 public:
  Object() = default;

  void SetName(const std::string &name) { name_ = std::move(name); }
  std::string GetName() const { return name_; }

 private:
  std::string name_;
};

UseObject라는 오버로드된 함수도 거의 없습니다.

void UseObject(Object &) {
  std::cout << "calling UseObject(Object &)" << std::endl;
}

void UseObject(const Object &) {
  std::cout << "calling UseObject(const Object &)" << std::endl;
}

void UseObject(Object &&) {
  std::cout << "calling UseObject(Object &&)" << std::endl;
}


이제 우리는 메인

int main() {
  Object object;
  const Object const_object;
  UseObject(object);
  UseObject(const_object);
  UseObject(std::move(object));
}


아래와 같이 출력이 생성됩니다.

calling UseObject(Object &)
calling UseObject(const Object &)
calling UseObject(Object &&)


지금 당장 UseObject 함수에 인수를 전달하려는 간단한 템플릿 함수가 있다고 가정해 보겠습니다.

template <typename T>
void NotForwardToUseObject(T x) {
  UseObject(x);
}


이제 코드 실행

int main() {
  Object object;
  const Object const_object;
  NotForwardToUseObject(object);
  NotForwardToUseObject(const_object);
  NotForwardToUseObject(std::move(object));
}


결과로

calling UseObject(Object &)
calling UseObject(Object &)
calling UseObject(Object &)


여기서 함수는 이전에 예상한 대로 호출되지 않습니다.

이는 constrvaluenessvoid NotForwardToUseObject(T x)에 대한 템플릿 공제에서 무시되기 때문입니다.

참조 매개 변수를 처리하려면 범용 참조 매개 변수만 전달된 인수의 lvalueness 및 rvalueness에 대한 정보를 인코딩하기 때문에 범용 참조를 사용해야 합니다.

이제 템플릿 인수에 범용 참조를 사용하면

template <typename T>
void HalfForwardToUseObject(T &&x) {  // universal reference
  UseObject(x);
}


코드 실행

int main() {
  Object object;
  const Object const_object;
  HalfForwardToUseObject(object);
  HalfForwardToUseObject(const_object);
  HalfForwardToUseObject(std::move(object));
}


결과로

calling UseObject(Object &)
calling UseObject(const Object &)
calling UseObject(Object &)


거의! const의 전달이 작동하는 것 같지만 인수의 rvalueness가 여전히 올바르게 전달되지 않습니다.

진정한 완벽한 전달을 위해서는 x를 원래 유형과 lvalue 또는 r-value-ness로 캐스팅해야 합니다.

template <typename T>
void ForwardToUseObject(T &&x) {
  UseObject(static_cast<T &&>(x));
}


이제 코드 실행

int main() {
  Object object;
  const Object const_object;
  ForwardToUseObject(object);
  ForwardToUseObject(const_object);
  ForwardToUseObject(std::move(object));
}


결과로

calling UseObject(Object &)
calling UseObject(const Object &)
calling UseObject(Object &&)


완벽한! 개체를 올바르게 전달했습니다.
코드를 단순화하기 위해 C++std::forward 라이브러리에서 <utility>를 사용할 수 있습니다.

template <typename T>
void PerfectForwardToUseObject(T &&x) {
  UseObject(std::forward<T>(x));
}


위의 예를 통해 이제 완벽한 전달이 무엇을 의미하는지 이해하셨기를 바랍니다.
평소와 같이 위의 코드는 mygithub에서 액세스할 수 있습니다.

포스팅 끝까지 읽어주셔서 감사합니다!

좋은 웹페이지 즐겨찾기