There is another option that uses inheritance and works as follows. For the last two arguments, it uses a class that actually inherits from a class that has two member templates that can be used to generate the necessary types. Because inheritance is virtual, the identifiers declared by it are shared between inheritance, as shown below.
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; };
Now you have the default argument that you are using, which has typedefs for the default arguments that you want to provide. Member templates will be parameterized with keys and value types.
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 will now be inferred from all template arguments. If the derived class VirtualRoot hides a member from the base, this member of the derived class will dominate the member and will be used, although the base class element can be reached in a different way in the Inheritance Tree.
Please note that you do not pay for virtual inheritance, because you never create an object of type use_policies . You use only virtual inheritance to use the dominance rule.
template<typename B, int> struct Inherit : B { }; template<class Pol1, class Pol2> struct use_policies : Inherit<Pol1, 1>, Inherit<Pol2, 2> { };
Since we potentially exit the same class more than once, we use the Inherit template template: Inheriting from the same class directly is twice forbidden. But his inheritance is indirectly permitted. Now you can use all this as:
MyClass<int, float> m; MyClass<float, double, ValueCompareIs< less<double> > > m;