Частично специализировать функцию-член шаблона - PullRequest
3 голосов
/ 12 августа 2010

У меня есть шаблон класса, который выглядит следующим образом:

template <template <class TypeT> class PoolT=pool_base>
struct pool_map
{
public:
  template <typename U> struct pool { typedef PoolT<U> type };

public:
  template <typename T, size_t S=sizeof(T)>
  T& get( size_t index );

private:
  pool<uint8_t>::type  pool8_;
  pool<uint16_t>::type pool16_;
  pool<uint32_t>::type pool32_;
  pool<uint64_t>::type pool64_;
};

template <template <class TypeT> class PoolT>
template <typename T, size_t S>
inline
T& pool_map<PoolT>::get( size_t index )
{
  // Default case
}

template <template <class TypeT> class PoolT>
template <typename T>
inline
T& pool_map<PoolT>::get<T,8>( size_t index )
{
  // Dispatch to pool8_
}

template <template <class TypeT> class PoolT>
template <typename T>
inline
T& pool_map<PoolT>::get<T,16>( size_t index )
{
  // Dispatch to pool16_
}

template <template <class TypeT> class PoolT>
template <typename T>
inline
T& pool_map<PoolT>::get<T,32>( size_t index )
{
  // Dispatch to pool32_
}

Вы, очевидно, заметили, что я написал то, что было бы возможно в прекрасном и идеальном мире, где возможны параметры шаблона по умолчанию и частичная специализация методов шаблона (без специализации всего класса).

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

Единственное решение, которое приходит мне в голову, - это использовать внешний класс get_pool<size_t>, который будет принимать pool_map в качестве параметров и возвращает ссылку на член poolX_, но я бы хотел этого избежать, так как он не похоже на "настоящий статический путь".

Спасибо за чтение!

Ответы [ 2 ]

3 голосов
/ 12 августа 2010

Существует одно простое решение (может быть, вы не думали об этом):

template <typename T>
T& pool_map<PoolT>::get( size_t index )
{
  if (sizeof(T) * CHAR_BIT == 8) {
     // Dispatch to pool8_
  } else if (sizeof(T) * CHAR_BIT == 16) {
     // Dispatch to pool16_
  } else if (...) {
     ...
  } else {
    // Default case
  }
}

Но так как это может привести к ошибкам компиляции (в зависимости от того, что вы поставили вместо «dispatch»)to ... ") вы можете просто перегрузить функцию get ().

template <typename T>
typename std::enable_if<sizeof(T) * CHAR_BIT == 8,T>::type&
    get( size_t index )
{
   ...
}

template <typename T>
typename std::enable_if<sizeof(T) * CHAR_BIT == 16,T>::type&
    get( size_t index )
{
   ...
}

etc.

Единственная проблема заключается в том, что для реализации по умолчанию (если она вам нужна) требуется условие типа sizeof(T) * CHAR_BIT != 8 && sizeof(T) * CHAR_BIT != 16 && sizeof(T) * CHAR_BIT != 32 && sizeof(T) * CHAR_BIT != 64

В последнем решении (лучшее, которое я бы сказал) по-прежнему использовался бы закрытый класс со статической функцией, которую вы можете специализировать (что, как вы сказали, не было "настоящим статическим способом")

0 голосов
/ 12 августа 2010

Одним из решений является использование enable_if и disable_if (обычно), хотя я не проверял его.

Другое решение - просто переслать детали реализации помощнику:

namespace helper
{
  template <class T> struct getter { static void Do() {} };

  // specializations by type
}

template <class T>
T& pool_map<T>::get(size_t index) { return helper::getter<T>::Do(); }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...