Уменьшение беспорядка шаблонной политики - PullRequest
2 голосов
/ 13 января 2012

Если у меня есть следующие параметры шаблона:

template <typename T_Key, typename T_Value, typename T_HashFunc, 
    typename T_ExtractKey, typename T_EqualKey, typename T_RehashClass, typename T_HashcodeClass>
  class Hashtable { /* ... */ };

Где T_RehashClass и T_HashcodeClass - это два класса шаблона, которые также принимают T_Key, T_Value, T_HashFunc, T_ExtractKey and T_EqualKey.Я бы хотел, чтобы эти классы брали типы из списка typedef Hashtable (все типы параметров шаблона в Hashtable определены type).

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

В любом случае, любойкласс, который является T_RehashClass, должен иметь заполненные параметры шаблона T_Key, T_Value и т. д., которые я вижу как дублирование кода.Я хотел бы, чтобы класс каким-то образом знал Hashtable, чтобы он мог обращаться к своим typedefs и автоматически выводить типы T_Key, T_Value и т.д., создавая свои собственные typedef.К сожалению, в этом случае я получаю циклическую зависимость.

Как обычно решается проблема такого типа?

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


Одно решение, которое яИдея заключалась в том, чтобы иметь структуру шаблона, которая имеет все параметры шаблона от T_Key до T_EqualKey.Тогда объявление Hashtable будет иметь вид:

template <typename T_HashtableParams, typename T_RehashClass = default_rehash_class<T_HashtableParams>, typename T_HashcodeClass = default_hashnode_class<T_HashtableParams> >
  class Hashtable { /* ... */ };

. T_RehashClass и T_HashcodeClass могут принять значения по умолчанию, что устранит дублирование кода.Проблема с этим подходом состоит в том, что он более громоздок для пользователя.

Ответы [ 2 ]

2 голосов
/ 14 января 2012

Я не уверен, что ужасно интересно указывать разные типы T_Key и T_Value для ваших классов hash и rehash. Если бы я решил эту проблему, я бы сначала попытался установить политику для ключа / val. Я склонен сказать, что, возможно, должен быть ValuePolicy вместо того, чтобы группировать его с KeyPolicy, но это ни здесь, ни там.

namespace hash {
namespace detail {

    template<
            typename Key
            , typename Value
            , typename KeyGetter
            , typename KeyComparator>
        class KeyPolicy {
        public:
            typedef Key key_t;
            typedef Value value_t;
            typedef KeyGetter get_t;
            typedef KeyComparator compare_t;
        };

}} // hash detail

HashTable недействителен, если у него нет той же KeyPolicy, что и для повторной, и т. Д., Поэтому не указывайте его.

namespace hash {
namespace detail {

    template<typename RehashPolicy>
        class HashTableImpl {
        public:
            typedef RehashPolicy rehash_p;
            typedef typename rehash_p::key_policy_t::key_t key_t;
            // typedef ...
        };

    // this doesn't have a specific name, its anything.
    template<typename KeyPolicy>
        class SomeRehashPolicy {
        public:
            typedef KeyPolicy key_policy_t;
        };

}} // hash detail

Вы можете добавить туда любые определения типов, которые вам нужны. Если бы я был приверженцем обзора кода, я бы, вероятно, попросил, чтобы такие вещи, как rehash_p и key_policy_t, были конфиденциальными. Это детали реализации, правда. Фактический инвариант, который вы пытаетесь защитить, это то, что находится в key_t и т. Д.

Может быть, я за пределами разумных границ этикета, но мое честное мнение состоит в том, что вся эта конфигурация интересна только парню, который ее написал. Ни ты, ни кто-либо, кто использует это. Так что я бы раскрыл только одну или две конфигурации HashTable, которые люди на самом деле собираются использовать.

namespace hash {

    struct stub {}; // sorry, I'm lazy

    template<typename Key, typename Value>
        class HashTable {
        private:
            typedef typename detail::KeyPolicy<Key, Value, stub, stub> key_p;
            typedef typename detail::SomeRehashPolicy<key_p> rehash_p;
            typedef typename detail::HashTableImpl<rehash_p> impl_t;
        public:
            typedef typename impl_t::key_t key_t;
        };

} // hash

int main(int argc, char ** argv) {
    hash::HashTable<int, double> hash_table;
    return 0;
}

Многие детали явно не заполнены, но вы поняли.

1 голос
/ 13 января 2012

См., Например, Modern C ++ Design (раздел 1.5.1: Реализация политик с параметрами шаблона-шаблона).Идея состоит в том, чтобы T_RehashClass и T_HashcodeClass были параметрами шаблона-шаблона.Эти классы принимают T_Key, T_Value и все остальное в качестве своих собственных параметров.Чтобы избежать перепечатывания, вы можете наследовать необходимые экземпляры этих шаблонов.

template <
    typename T_Key, 
    typename T_Value, 
    typename T_HashFunc,      
    typename T_ExtractKey, 
    typename T_EqualKey, 
    template<typename, typename /*, more params */> class T_RehashClass, 
    template<typename, typename /*, more params */> class T_HashcodeClass
>   class Hashtable 
:
    public T_RehashClass<T_Key, T_Value /*, more params */>,
    public T_HashcodeClass<T_Key, T_Value /*, more params */>
{ /* ... */ }; 

ПРИМЕЧАНИЕ: вам действительно нужен "class", а не "typename" перед T_RehashClass и T_HashcodeClass, поскольку они являются именами шаблонов, а нетипы шаблонов!

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