C++ - 자주 사용하는 C++ 이디엄(idiom) CRTP

CRTP는 Curiously Recurring Template Pattern의 약어로 자주 직역되고 있지만 기묘하게 재기한 템플릿 패턴이라고 부른다.

template<class Inher>

struct X{};

struct Derived:X<Derived>{}; // CRTP

기본 클래스에서 파생 클래스를 볼 수 있으므로 이것을 이용한 다양한 패턴도 다시 생겨나고 있다.
예를 들면 순수 가상 함수 등을 이용하지 않고 정적으로 파생 클래스에 대해서 해당 구현을 강요하는 등.

template<class Tp>
struct base{
    void f()const{static_cast<Tp>(this)->f();}
};
struct derived:private base<derived>{
    void f() const {}
};

그러나 이 기술만으로는 파생 클래스에서는 구현을 하지 않고도 멤버를 호출하지 않으면 오류를 내지 않으므로 아래처럼 한다.

template<class Tp,void (Tp::*)()>
struct signature_f_1{using type=Tp;};

template<class Tp,class=Tp>
struct signature_f_2:std::false_type{};
template<class Tp>
struct signature_f_2<Tp,typename signature_f_1<Tp,&Tp::f>::type>:std::true_type{};

template<class Tp>
constexpr bool signature_f_v=signature_f_2<Tp>::value;

template<class Derived>
struct base{
    virtual ~base()=default;
    base(){static_assert(signature_f_v<Derived>,"u must define function f");}
    void f(){return static_cast<Derived*>(this)->f();}
};
template<class Tp>
class equal_comp{
    friend bool operator!=(const Tp& lhs,const Tp& rhs){return !lhs.operator==(rhs);}
};

class X final:equal_comp<X>{
    std::string s;
public:
    bool operator==(const X& rhs)const{return rhs.s==s;}
    explicit X(const std::string& s):s(s){}
};

int main()
{
    using namespace std::string_literals;
    X a("hoge"s),b("foo"s);
    assert(a!=b);
}

==!= 처럼 각각의 연산자가 쌍을 이루고 있는 연산자는 한쪽 구현이 확정된 순간에 당연히 다른 구현이 확립되므로 자동 생성이 가능하다.


이 글은 2020-05-27에 작성되었습니다.