CRTP

CRTP(Curiously Recurring Template Pattern)
CRTP는 상속과 템플릿 프로그래밍을 효율적으로 결합한다.
class pointer{
public:
point(int x, int y): x(x), y(y) {}
bool operator==(const point& that) const {
return x==that.x && y==that.y;
}
bool operator!=(const point& that) const {
return x!=that.x || y!=that.y;
// or
// return !(*this==that);
}
private:
int x, y;
};
템플릿 프로그래밍 사용
template <typename T>
struct inequality{
bool operator!=(const T& that) const {
return !(static_cast<const T&>(*this)==that);
}
};
class point: public inequality<point>{ /* ... */ };
위와 같이 템플릿 클래스를 상속해서 해당 기능을 사용할 수 있다.

상호 의존성 수립
- point는 inequality로 부터 파생되었다.
- inequality는 point로 매개변수화
하지만, 템플릿 클래스의 멤버 함수를 호출하기 전까지 컴파일되지 않기 때문에 컴파일 가능함
point p1(3, 4), p2(3, 5);
cout<<"p1 != p2 is "<<boolalpha<<(p1!=p2)<<'\n';
point 클래스에서 operator!=를 먼저 찾은 후, 찾지 못할 경우
base_class inequality<point>의 operator!=를 사용한다.
재사용 가능한 접근 연산자
첨자 연산자를 재사용할 수 있도록 구현해 다차원 자료 구조에 접근
class some_matrix;
class simple_bracket_proxy{
public:
simple_bracket_proxy(matrix& A, size_t r): A(A), r(r) {}
double& operator[](size_t c){ return A(r, c); } // error
private:
some_matrix& A;
size_t r;
};
class some_matrix{
// ...
double& operator()(size_t r, size_t c){ /* ... */ }
simple_bracket_proxy operator[](size_t r){
return simple_bracket_proxy(*this, r);
}
};
위에서 some_matrix를 전방 선언은 해주었지만, 완전히 정의되지 않았기 때문에 operator()를 호출하면,
에러를 출력한다.
(서로 의존하는 두 타입이 서로 완전히 정의되어야 한다.)

템플릿에서 코드 생성이 연기되기 때문에, 상호 의존성을 깨뜨릴 수 있다.
template <typename Matrix, typename Result>
class bracket_proxy{
public:
bracket_proxy(Matrix& A, size_t r): A(A), r(r) {}
Result& operator[](size_t c){ return A(r, c); }
private:
Matrix& A;
size_t r;
};
class some_matrix{
// ...
bracket_proxy<some_matrix, double> operator[](size_t r){
return bracket_proxy<some_matrix, dobule(*this, r);
}
};
CRTP 클래스를 추가해 첨자 연산자를 한번만 구현
template <typename Matrix, typename Result>
class bracket_proxy{ /* ... */ };
template <typename Matrix, typename Result>
class crtp_matrix{
using const_proxy=bracket_proxy<const Matrix, const Result>;
public:
bracket_proxy<Matrix, Result> operator[](size_t r){
return {static_cast<Matrix&>(*this), r};
}
const_proxy operator[](size_t r) const {
return {static_cast<const Matrix&>(*this), r};
}
};
class matrix: public crtp_matrix<matrix, double>{
// ...
}