템플릿
템플릿 클래스에 타입을 지정하여 객체를 생성하는 것을 템플릿 인스턴스화라고 한다.
컴파일러는 템플릿 메서드 정의 코드를 만나면 문법은 검사하지만 실제로 컴파일은 하지 않는다.
어떤 타입이 사용될지 알 수 없기 때문에 템플릿 정의 구문 자체는 컴파일할 방법이 없기 때문이다.
템플릿은 그저 번거로운 복사/붙여넣기와 단어 바꾸기 작업을 대신해줄 뿐이다.
컴파일러는 제네릭 클래스의 모든 버추얼 메서드에 대해 코드를 생성한다.
하지만 버추얼 메서드가 아닌 경우 특정 타입이 지정되고 실제 호출되는 것만 코드를 생성한다.
타입을 특정하지 않고 코드를 작성할 때는 작성하는 코드의 내용으로부터 타입을 만족시켜야 하는 요건들이 발생한다.
템플릿을 인스턴스화할 때 지정된 타입이 템플릿 코드에서 필요로 하는 동작을 지원하지 않는다면 컴파일에 실패하게 된다.
사용할 타입이 특정 동작을 지원하지 않으면 실제 사용하는 코드만 인스턴스화하는 템플릿의 특성을 활용해서 컴파일 에러없이 템플릿을 이용할 수 있다.
템플릿 파라미터는 한개뿐 아니라 여러개의 템플릿 파라미터로 설정할 수 있다. 추가되는 파라미터는 꼭 타입이 아니더라도 가능하다.
타입이 아닌 템플릿 파라미터는 정수 타입 값(char, int, long 등), 열거 타입 값, 포인터 값, 참조형 변수같은 것들만 가능하다.
C++는 클래스의 개별 메서드도 템플릿화 할 수 있다. 템플릿 메서드를 만드는 것은 사실상 한꺼번에 수많은 버전의 메서드를 만드는 것과 같은 효과가 있다.
템플릿 메서드는 템플릿 클래스의 대입 연산자나 복제 연산자를 만들 때 특히 유용하다.
버추얼 메서드와 소멸자는 템플릿 메서드로 만들 수 없다.
템플릿 대입 연산자에서는 자기 대입을 체크하여 예외 처리할 필요가 없다. 자기 대입은 템플릿이 아닌 컴파일러가 생성한 일반 버전의 operator=를 호출하기 때문에
템플릿 버전에서는 자기 대입이 발생하지 않는다.
이것은 복제 생성자도 마찬가지이다.
T()는 T가 클래스 타입일 경우 디폴트 생성자를 호출하고 class 타입이 아니면 0으로 초기화한다. 이러한 초기화방식을 0 초기화 문법이라고 한다.
템플릿 특수화는 특정 타입에 한하여 원본 템플릿 구현을 대체하는 새로운 클래스를 작성할 수 있게 한다.
템플릿 특수화는 어떤 코드도 상속받지 않는다. 특수화는 클래스 파생이 아니다. 따라서 클래스 전체를 재작성해야 한다.
템플릿 클래스를 상속받는 클래스도 만들 수 있다. 만약 파생 클래스가 인스턴스화되지 않은, 즉 타입이 지정되지 않은 템플릿 클래스 원본 자체를
상속받는 경우 해당 파생 클래스도 템플릿이어야한다. 만약 템플릿 클래스의 특정 인스턴스를 상속받는다면 파생 클래스가 꼭 템플릿일 필요는 없다.
C++의 템플릿 상속에 대한 이름 룩업 방식 때문에 데이터 멤버에 대한 접근을 어디에 정의되어있는지 구체적으로 지정해야 한다. 예) Grid::kDefaultWidth
이름 룩업 방식 때문에 베이스 클래스의 데이터 멤버와 메서드에 접근할 때는 this포인터를 사용해야한다.
typedef 대신 템플릿 에일리어스를 이용해 타입을 재정의한다. using OtherName = MyTemplateClass;
새로운 함수 정의 문법이 도입된 이유는 함수 프로토타입을 정의할 때 리턴 타입이 어떻게 될지 알 수 없는 경우가 많기 때문이다.
auto myFunc(const Type& t1, const Type2& t2) -> decltype(t1 + t2)를 이용해서 t1+t2리턴타입을 컴파일타임에 알수있다.
-> decltype(t1 + t2) 는 C++14 표준에서 생략 가능하다. 결정되는 타입이 파라미터 이후에 오기때문에 컴파일러가 타입을 알수있게 된다.
템플릿 함수는 템플릿 클래스에서 연산자 오버로딩을 할 때 유용하게 사용된다.
전역 함수로 하는 operator 템플릿 함수에 friend선언을해서 각 템플릿 클래스마다 1:1대응을 시켜서 데이터 멤버에 접근가능케한다.
니애미
굳