-
항목27. 보편 참조에 대한 중복적재 대신 사용할 수 있는 기법들을 알아 두라Effective Modern C++ 2022. 9. 6. 20:22
1. 중복적재를 포기하라
중복적재 대신 다른 이름의 함수 2개를 만들어라.
logAndAdd -> logAndAddName & logAndAddNameIdx
2. const T& 매개변수를 사용한다.
이동대신 복사가 되는 등 효율성이 떨어지지만 보편참조와 중복적재의 상호작용에 의한 문제점은 피할 수 있다.
3. 값 전달 방식의 매개변수를 사용한다.
class Person{ public: explicit Person(std::string n) // T&& 생성자를 대체한다. : name(std::move(n)) {} explicit Person(int idx) : name(nameFromIdx(idx)) {} ... private: std::string name; };int류 형식을 받으면 int를 받는 중복적재가, std::string 형식의 모든 인수는 std::string 을 받는 생성자가 선택.
4. 꼬리표 배분을 사용한다.
template<typename T> void logAndAdd(T&& name) { logAndAddImpl(std::forward<T>(name), std::is_integral<typename std::remove_reference<T>::type>() ); } // 레퍼런스를 제거하지 않으면 왼값 int 는 T에 int&로 연역됨. // 그래서 레퍼런스를 제거해줘야함// std::false_type은 컴파일 시점 형식 // false,true는 실행 시점 형식 template<typename T> void logAndAddImpl(T&& name,std::false_type) { ... } template<typename T> void logAndAddImpl(int idx,std::true_type) { ... }std::false_type , std::true_type 형식들이 꼬리표 이다
5. 보편 참조를 받는 템플릿을 제한한다.
class Person{ public: template< typename T, typename = typename std::enable_if< // *여기부터* !std::is_base_of<Person, typename std::decay<T>::type >::value && !std::is_integral< typename std::remove_reference<T>::type >::value >::type // *여기까지 조건에 해당한다.* > explicit Person(T&&) : name(std::forward<T>(n)) { ... } explicit Person(int idx) : name(nameFromIdx(idx)) { ... } ... };std::enable_if<조건>::type . 즉, Person 과 T가 같지 않으면 보편참조를 받는 생성자 활성화.
(Person 와 T가 같으면 비활성화)
typename =
typename std::enable_if<!std::is_same<Person ,typename std::decay<T>::type >::value>::type
=> 여기서 추가로 Person을 기반 클래스로한 파생 클래스를 받는 생성자를 호출할 때도 물론 보편참조를 생성자를 제외해야한다. 그래서 std::is_same => std::is_base_of로 변경하면 된다.
std::is_base_of<T1,T2>::value . T2가 T1에서 파생된 형식이면 참이다.
(std::is_base_of<T,T>::value T가 사용자 정의 형식이면 참이다. 사용자 정의 형식이 아니면 거짓이다.)
이 과정을 통해 위의 코드가 완성됐다. 이런 방식과 똑같은 절차로 정수 인수를 위한 생성자 중복적재를 만들고 문제들을 해결할 수 있다.
+. static_assert(std::is_constructible<T1, T2>::value,"경고문")
생성자 본문안에 넣어서 사용가능. T2로 부터 T1을 생성할 수 있는지 판정한다.
'Effective Modern C++' 카테고리의 다른 글
항목29. 이동 연산이 존재하지 않고, 저렴하지 않고, 적용되지 않는다고 가정하라 (0) 2022.09.24 항목28. 참조 축약을 숙지하라 (0) 2022.09.07 항목26. 보편 참조에 대한 중복적재를 피하라 (0) 2022.09.06 항목25. 오른값 참조에는 std::move를, 보편 참조에는 std::forward를 사용하라 (0) 2022.08.27 항목24. 보편 참조와 오른값 참조를 구별하라 (0) 2022.08.27