2015-04-27 5 views
2

Я начинаю изучать идиому CRTP, и я заметил, что GCC имеет флаг fdevirtualize, который должен позволять преобразовывать, когда это возможно, вызовы vtable для прямых вызовов.CRTP против флага девиртуализации в GCC

Хотя CRTP можно применять с любым (C++-совместимым) компилятором, если я хочу развивать только с помощью gcc, могу ли я избежать идиомы CRTP, оставляя gcc процесс девиртуализации, или всегда лучше использовать его, когда это возможно, чтобы использовать статический полиморфизм, чтобы избежать вызовов виртуальных функций?

ответ

4

Девиртуализация может помочь или нет, в зависимости от того, строит ли ваш компилятор ваш материал.

Обратите внимание, что CRTP обычно используется для реализации миксинов и шаблона метода шаблона, например. как это:

template <typename T, typename Derived> 
class pointer_base { 
    const Derived& self() const { return static_cast<const Derived&>(*this); } 
public: 
    T& operator *() const { return *self().get(); } 
    T* operator ->() const { return self().get(); } 
}; 

template <typename T> 
class smart_pointer : public pointer_base<T, smart_pointer<T>> { 
public: 
    T* get() const; 
}; 

И форме виртуального вызова:

template <typename T> 
class pointer_base { 
protected: 
    ~pointer_base() = default; 
public: 
    virtual T* get() const = 0; 
    T& operator *() const { return *get(); } 
    T* operator ->() const { return get(); } 
}; 

template <typename T> 
class smart_pointer : public pointer_base<T> { 
public: 
    T* get() const override; 
}; 

Использование в любом случае

smart_pointer<int> p(new int); 
*p = 42; 

Обратите внимание, что там может быть несколько различных смарт-классов указатель. В версии виртуальной функции все они происходят из одного и того же pointer_base. Это означает, что существует одна версия базовой функции, которая будет использоваться для всех из них. И если это так, девиртуализация не может работать.

Он будет работать только в том случае, если соответствующая функция встроена в вызывающего абонента, потому что тогда компилятор может специализировать код для конкретного конкретного типа интеллектуального указателя.

Конечно, с помощниками, настолько маленькими, шансы на то, что они становятся вложенными, высоки. С другой стороны, теперь у вас есть класс pointer_base, который клиенты видят и могут испытывать соблазн использовать. Вы можете получить конфиденциальность из базы, но затем вам нужно добавить использование объявлений для всех участников, которые вы хотите открыть в каждом производном классе. С такими классами, как pointer_base, который состоит из лотов (2 в моем случае, но на самом деле также должно быть логическое преобразование) небольших функций, это раздражает. Но тогда и синтаксический беспорядок CRTP. Думаю, дело доходит до вкуса.

Когда у вас есть только один, большой метод шаблона, компилятор не сделает его наиболее вероятным. В этом случае он не может девитировать. Но CRTP имеет свой собственный недостаток: метод дублируется для каждого экземпляра базы, независимо от того, хотите вы этого или нет. Это может привести к раздуванию кода.

Таким образом, это в конечном итоге сводится к обычному вопросу о шаблонах и виртуальных функциях: специализированный код с соответствующим увеличением размера кода или ограничение производительности виртуальных вызовов и встроенный барьер, который они создают.

+0

Отличное объяснение, спасибо. – Jepessen