language_crtp
language_crtp (이상하게 반복되는 템플릿 패턴, CRTP)
Curiously Recurring Template Pattern은 클래스 X가 템플릿 매개변수 Z를 받는 클래스 템플릿 Y로부터, Z = X로 인스턴스화하여 파생되는 관용구예요. 컴파일 타임 다형성을 구현하는 대표적인 기법이에요.
출처: cppreference
본문
예를 들어 다음과 같이, 클래스 X가 자기 자신을 템플릿 인자로 넘긴 Y<X>로부터 상속받아요.
template<class Z>
class Y {};
class X : public Y<X> {};
예제
CRTP는 "컴파일 타임 다형성"을 구현하는 데 쓸 수 있어요. 기반 클래스가 인터페이스를 노출하고, 파생 클래스가 그 인터페이스를 구현하는 방식이에요.
#include <cstdio>
#ifndef __cpp_explicit_this_parameter // 전통적인 문법
template <class Derived>
struct Base
{
void name() { static_cast<Derived*>(this)->impl(); }
protected:
Base() = default; // Base 객체 생성 방지 (UB)
};
struct D1 : public Base<D1> { void impl() { std::puts("D1::impl()"); } };
struct D2 : public Base<D2> { void impl() { std::puts("D2::impl()"); } };
#else // C++23 deducing-this 문법
struct Base { void name(this auto&& self) { self.impl(); } };
struct D1 : public Base { void impl() { std::puts("D1::impl()"); } };
struct D2 : public Base { void impl() { std::puts("D2::impl()"); } };
#endif
int main()
{
D1 d1; d1.name();
D2 d2; d2.name();
}
출력:
D1::impl()
D2::impl()
전통적인 CRTP에서는 기반 클래스가 static_cast<Derived*>(this)->impl()처럼 자기 타입을 Derived로 캐스팅해 파생 클래스의 구현을 호출해요. C++23부터는 deducing this 문법으로 더 간결하게 쓸 수 있어요. 이렇게 하면 가상 함수 호출 없이 컴파일 타임에 바인딩되는 다형적 동작을 만들 수 있어요.