Как специализировать шаблон для типа, производного от определенного типа - PullRequest
5 голосов
/ 30 марта 2012

У меня есть класс World, который управляет созданием объекта ... После создания он вызывает метод afterCreation, и я создал объект определенного пользователем типа, производного от Entity (например, MyEntity), я хочу вызватьaddEntity.У меня объект был чем-то другим, я ничего не хочу делать.addEntity должен вызываться с соответствующим T, потому что он генерирует уникальные идентификаторы для каждого производного класса и т. Д.

Вот мое решение:

template <int v>
struct ToType
{
    enum { value = v };
};

template <typename T>
void World::afterCreation(T * t)
{
    afterCreation(t, ToType<std::is_base_of<Entity, T>::value>());
}

template <typename T>
void World::afterCreation(T * t, ToType<true>)
{
    addEntity(t); //here I cant pass Entity *, I need the real type, eg. MyEntity
}

template <typename T>
void World::afterCreation(T * t, ToType<false>)
{

}

Мой вопрос - может быть всделано лучше?

Как я могу смоделировать следующий код без ToType или подобного?

template <typename T>
void afterCreation(){/*generic impl*/}

template <typename T where T is derived from Entity>
void afterCreation(){/*some specific stuff*/}
  • «специализировать» в названии только для описания моих намерений, нет необходимостирешить проблему со специализацией шаблона

Ответы [ 2 ]

3 голосов
/ 30 марта 2012

Это не станет намного лучше, но вы можете удалить один уровень косвенности, используя SFINAE:

template <typename T>
typename std::enable_if< std::is_base_of<Entity, T>::value >::type
 World::afterCreation(T * t)
{
   // Derived from Entity
}
template <typename T>
typename std::enable_if< !std::is_base_of<Entity, T>::value >::type
 World::afterCreation(T * t)
{
   // generic
}

Как это работает? Когда компилятор находит вызов afterCreation, он пытается определить, какая из перегрузок является best , и для этого он сопоставляет типы и пытается выполнить подстановку. В обоих случаях сопоставляется тип (из аргументов) и применяется подстановка ко всему выражению. Шаблон enable_if содержит внутренний тип type, если значением, переданным в качестве первого аргумента, является true, или же он не содержит такого типа. При замене типов одна из перегрузок выдаст недопустимую сигнатуру функции (ту, для которой условие имеет значение false) и будет удалена из набора кандидатов.

1 голос
/ 30 марта 2012

Вы можете сделать это с помощью полиморфных указателей:

template <typename T>
void afterCreation(T* x) {
    T* entity = dynamic_cast<Entity*> x;

    if (!entity) {
        // ... generic implementation
    } else {
        // ... entity implementation, use "entity"
    }
}

Хотя это может быть не лучшим решением, так как оно имеет (крошечные) накладные расходы времени выполнения. Очень умный компилятор может устранить эти издержки с помощью статического анализа, но я сомневаюсь, что компиляторы подберут это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...