1. 보편 참조에 대한 중복 적재는 거의 항상 보편 참조, 중복 적재 버전이 예상보다 자주 호출되는 상황으로 이어진다.
2. 완벽 전달 생성자들은 문제가 많다. 그런 생성자는 대체로 비const 왼 값에 대한 복사 생성자보다 더 나은 부합이며, 기반 클래스 복사 및 이동 생성자들에 대한 파생 클래스의 호출들을 가로챌 수 있기 때문이다.
//보편 참조 버전
template<typename T>
void logAndAdd(T && name)
{
auto now = std:; chrono::system_clock::now();
log(now, "logAndAdd");
names.emplace(std:; forward<T>(name));
}
//int 오버로딩 함수
void logAndAdd(int idx)
{
auto now = std::chrono::system_clock::now();
log(now, "logAndAdd");
names.emplace(nameFromIdx(idx));
}
// short nameIdx는 보편 참조 버전을 사용할까? int 오버로딩 함수를 사용할까?
// 컴파일러는 승격보다 정확한 부합을 더 우선순위 처리하기 때문에
// (예기치 않은)보편 참조를 사용하게 되고 보편참조는 string을 고려하고 있기 때문에 에러가 발생한다.
short nameIdx;
logAndAdd(nameIdx);
항목 27. 보편 참조에 대한 중복적재 대신 사용할 수 있는 기법들을 알아두라
1. 중복 적재를 포기한다. (함수 이름을 다르게 한다던가)
2. const T& 매개변수를 사용한다.
3. 값 전달 방식의 매개변수를 사용한다.(1번과 비슷한 이유로 아예 정확히 타입을 명시한다.)
4. 꼬리표 배분을 사용한다. (중간 함수를 둬서 우리가 원하는 방식으로 제어한다.)
5. 보편 참조를 받는 템플릿을 제한한다.
- std::enable_if 라는 것이 존재하는데 이는 컴파일러에게 특정 템플릿이 존재하지 않는 것처럼 행동하게 만들 수 있다.
6. 절충점들 (assert를 이용하여 금지된 타입들을 확인할 수 있게 한다.)
항목 28. 참조 축약을 숙지하라
: 참조의 참조의 참조...가 생기면(&& & && T)그 값은 하나의 참조(&T)가 된다.
: 만일 두 참조 중 하나라도 lvalue 참조이면 결과는 lvalue이고 그렇지 않으면 rvalue이다.
참조 축약이 일어나는 경우
1. 템플릿 인스턴스화
2, auto 변수에 대한 형식 연역
3. typedef 사용
4. decltype 사용
항목 29. 이동 연산이 존재하지 않고, 저렴하지 않고, 적용되지 않는다고 가정하라
- 지원하지 않는 경우가 많다
- 이동과 복사의 비용이 비슷할 수 있다.
1. 이동 연산이 없다.
2, 이동 연산이 더 빠르지 않다.
3. 이동 연산을 사용할 수 없다.
항목 30. 완벽 전달이 실패하는 경우들을 잘 알아두라
: 말 그대로 주소값, 특성 모두 완벽하게 전달되는 것
1. 완벽 전달은 템플릿 형식 연역이 실패하거나 틀린 형식을 연역했을 때 실패한다. (의도치 않은 타입으로 연역)
2.
인수가 중괄호 초기치이거나 0 또는 NULL로 표현된 널 포인터(NULL이라면 int로 완벽 전달이 이루어질 수 있다.)
선언만 된 정수 static_const 및 constexpr 자료 멤버, 템플릿 및 중복 적재된 함수 이름, 비트 필드이면 완벽 전달이 실패할 수 있다.