Какой самый простой способ сделать код функции шаблона в зависимости от типа параметра - PullRequest
1 голос
/ 07 февраля 2012

Я хочу написать шаблонную функцию, которая проверяет некоторое свойство Timestamp (класс наследует от Timed), но также должна работать для типов, которые не имеют отметки времени. Лучшее (и все еще довольно уродливое) решение, которое я нашел, состоит в следующем:

class Timed {
  protected:
    int mTime;        
  public:
    explicit Timed(int time=0): mTime(time){}
    int getT() const {return mTime;}

};

template<typename T>
bool checkStale(T const* ptr) const {
  return checkStaleImp(ptr, boost::is_base_of<Timed, T>() );
}

template<typename T>
template<bool b>
bool checkStaleImp(T const* ptr, boost::integral_constant<bool, b> const &){
  return true;
}

template<typename T>
bool checkStaleImp(T const* ptr, boost::true_type const&){
  const int oldest = 42;
  return (42 <= ptr->getT());  
}

Это три функции для одной функциональности. Есть ли более простой способ сделать это, например, используйте boost::is_base_of или что-то еще аналогично условию if или boost :: enable if для преобразования вывода функции в своего рода константу для классов, не производных от Timed. Решения с виртуальными функциями, к сожалению, не подходят.

Ответы [ 3 ]

5 голосов
/ 07 февраля 2012

Вы можете сделать то же самое с двумя простыми перегрузками и без шаблонного механизма:

bool checkStale(void const* ptr){
  return true;
}

bool checkStale(Timed const* ptr){
  const int oldest = 42;
  return (oldest <= ptr->getT());  
}

Нет необходимости в отправке тегов на is_base_of.

3 голосов
/ 07 февраля 2012

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

template<typename T>
bool checkStale(T const* ptr) const 
{
  struct local
  {
      static bool checkStaleImp(T const* ptr, boost::false_type const &)
      {
         return true;
      }
      static bool checkStaleImp(T const* ptr, boost::true_type const&)
      {
        const int oldest = 42;
        return (42 <= ptr->getT());  
      }
  };
  return local::checkStaleImp(ptr, boost::is_base_of<Timed, T>());
}

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

Кстати, в C ++ 11 вы можете использовать std::is_base_of вместо версии Boost.То же самое с std::true_type и std::false_type.

0 голосов
/ 07 февраля 2012

Используйте enable_if для выбора между возможными перегрузками.Поскольку условия, использованные в следующем примере, являются дополнительными, всегда будет доступна только одна перегрузка, и, следовательно, нет никакой неоднозначности

template<typename T>
typename std::enable_if<std::is_base_of<Timed,T>::value,bool>::type
checkStale(T const *ptr) const {
    const int oldest = 42;
    return oldest <= ptr->getT();
}

template<typename T>
typename std::enable_if<!std::is_base_of<Timed,T>::value,bool>::type
checkStale(T const *ptr) const {
    return true;
}
...