Существует еще одна опция, которая использует наследование и которая работает следующим образом. Для последних двух аргументов он использует класс, который наследуется практически от класса, имеющего два шаблона членов, которые можно использовать для генерации необходимых типов. Поскольку наследование является виртуальным, объявленные им typedefs распределяются между наследниками, как показано ниже.
template<class KeyType,
class ValueType,
class Pol1 = DefaultArgument,
class Pol2 = DefaultArgument>
class MyClass {
typedef use_policies<Pol1, Pol2> policies;
typedef KeyType key_type;
typedef ValueType value_type;
typedef typename policies::
template apply_key_compare<KeyType>::type
key_compare;
typedef typename policies::
template apply_value_compare<ValueType>::type
value_compare;
};
Теперь у вас есть аргумент по умолчанию, который вы используете, который имеет typedefs для аргументов по умолчанию, которые вы хотите предоставить. Шаблоны элементов будут параметризованы ключом и типом значения
struct VirtualRoot {
template<typename KeyType>
struct apply_key_compare {
typedef AnObnoxiouslyLongSequenceOfCharacters<KeyType>
type;
};
template<typename ValueType>
struct apply_value_compare {
typedef AnObnoxiouslyLongSequenceOfCharacters<ValueType>
type;
};
};
struct DefaultArgument : virtual VirtualRoot { };
template<typename T> struct KeyCompareIs : virtual VirtualRoot {
template<typename KeyType>
struct apply_key_compare {
typedef T type;
};
};
template<typename T> struct ValueCompareIs : virtual VirtualRoot {
template<typename ValueType>
struct apply_value_compare {
typedef T type;
};
};
Теперь use_policies
будет производным от всех аргументов шаблона. Если производный класс VirtualRoot
скрывает член от базы, этот член производного класса доминирует над членом базы и будет использоваться, даже если член базового класса может быть достигнут другим путем в наследственное дерево.
Обратите внимание, что вы не платите за виртуальное наследование, потому что вы никогда не создаете объект типа use_policies
. Вы используете только виртуальное наследование, чтобы использовать правило доминирования.
template<typename B, int>
struct Inherit : B { };
template<class Pol1, class Pol2>
struct use_policies : Inherit<Pol1, 1>, Inherit<Pol2, 2>
{ };
Поскольку мы потенциально являемся производными от одного и того же класса более одного раза, мы используем шаблон класса Inherit
: наследование одного и того же класса напрямую дважды запрещено. Но косвенное наследование разрешено. Теперь вы можете использовать все это следующим образом:
MyClass<int, float> m;
MyClass<float, double, ValueCompareIs< less<double> > > m;