태그 보관물: virtual

virtual

동적 다형성을 피하기위한 CRTP 가상 멤버 함수의 오버 헤드를 피하기

가상 멤버 함수의 오버 헤드를 피하기 위해 C ++에서 CRTP를 어떻게 사용할 수 있습니까?



답변

두 가지 방법이 있습니다.

첫 번째는 유형의 구조에 대해 인터페이스를 정적으로 지정하는 것입니다.

template <class Derived>
struct base {
  void foo() {
    static_cast<Derived *>(this)->foo();
  };
};

struct my_type : base<my_type> {
  void foo(); // required to compile.
};

struct your_type : base<your_type> {
  void foo(); // required to compile.
};

두 번째는 reference-to-base 또는 pointer-to-base 관용구를 사용하지 않고 컴파일 타임에 연결하는 것입니다. 위의 정의를 사용하면 다음과 같은 템플릿 함수를 가질 수 있습니다.

template <class T> // T is deduced at compile-time
void bar(base<T> & obj) {
  obj.foo(); // will do static dispatch
}

struct not_derived_from_base { }; // notice, not derived from base

// ...
my_type my_instance;
your_type your_instance;
not_derived_from_base invalid_instance;
bar(my_instance); // will call my_instance.foo()
bar(your_instance); // will call your_instance.foo()
bar(invalid_instance); // compile error, cannot deduce correct overload

따라서 함수에서 구조 / 인터페이스 정의와 컴파일 타임 유형 추론을 결합하면 동적 디스패치 대신 정적 디스패치를 ​​수행 할 수 있습니다. 이것이 정적 다형성의 본질입니다.


답변

나는 CRTP에 대한 적절한 토론을 찾고있었습니다. Todd Veldhuizen의 Techniques for Scientific C ++ 는이 (1.3) 및 표현식 템플릿과 같은 다른 많은 고급 기술에 대한 훌륭한 리소스입니다.

또한 Google 도서에서 Coplien의 원본 C ++ Gems 기사 대부분을 읽을 수 있음을 발견했습니다. 아마도 그럴 수도 있습니다.


답변

나는 CRTP 를 찾아야했다 . 그러나 그렇게 한 후 Static Polymorphism 에 대한 몇 가지 사항을 발견했습니다 . 이것이 귀하의 질문에 대한 대답이라고 생각합니다.

그것은 밝혀 ATL은 매우 광범위하게이 패턴을 사용합니다.


답변

Wikipedia 답변에는 필요한 모든 것이 있습니다. 즉:

template <class Derived> struct Base
{
    void interface()
    {
        // ...
        static_cast<Derived*>(this)->implementation();
        // ...
    }

    static void static_func()
    {
        // ...
        Derived::static_sub_func();
        // ...
    }
};

struct Derived : Base<Derived>
{
    void implementation();
    static void static_sub_func();
};

이게 실제로 얼마나 당신을 사는지 모르겠지만. 가상 함수 호출의 오버 헤드는 다음과 같습니다 (물론 컴파일러에 따라 다름).

  • 메모리 : 가상 기능 당 하나의 함수 포인터
  • 런타임 : 하나의 함수 포인터 호출

CRTP 정적 다형성의 오버 헤드는 다음과 같습니다.

  • 메모리 : 템플릿 인스턴스화 당 기본 복제
  • 런타임 : 하나의 함수 포인터 호출 + static_cast가 수행하는 모든 작업

답변