Internal Policy Designators

Synopsis

Itís common for high-end flexible template classes to be customizible through the use of helper classes. Having a parameterized “traits” class is powerful, and easy to specify custom traits explicitly, but difficult to create a default for new classes. Specifically, making an explicit specialization of a template class in a different namespace is awkward. Here I describe a way of making that easier.

Original version: October 18, 2004, formatting typos fixed October 20
Source Code File

Overview of the Problem

Suppose my library is in namespace N1. That is, all my headers with all my global stuff, including templates, are surrounded by namespace N1 { ... }. In my library I have a traits template, say Traits<T>. Referenced from outside the libraryís own implementation, thatís actually N1::Traits<T>.

A user of the library can supply a traits class as an explicit template argument, such as a class mytraits, but the default is Traits<T>, and for any class T youíll always use the same traits, that is supposed to go with that class.

template <typename T, typename ContainerPolicy<T> >
class container {
  

That is, you donít want to have to say container <C, mytraits> every time, with container <C> without the second argument probably being wrong. Instead, the idea is that when you write C with the intention of using it in container, youíll write class Traits<C> to go with it. Then any use of container will automatically pick up the correct traits.

However, his source file is surrounded by namespace N2 {…}, which is not a parent of N1. If he attempts to code:

template<> class N1::Traits<C> { blah blah }

he will get an error saying that he is not allowed to do that.

The only solution is to close N2, open N1, write the specialization, and then close N1 and re-open N2. Yuck, especially if rather deep in internal namespaces!

I have several templates that want to have “policies” associated rather strongly with the primary type, so I want a better way to do that. I use the terms policies and triats interchangably, since both terms are in common use for identical use of the C++ language features.

Survey of Approaches

Overloaded Functions

Rather than using a template specialization for this, I like using overloaded functions instead. The compiler will use argument-dependant lookup and find his overloaded version of the function that is defined to go with that class. The user can define the function in his own namespace right after the class itself.

This is fine for run-time selection of a single behavior. But for multiple related behaviors you need a function that returns an instance of a policy class, and it starts becoming less trivial.

For compile-time selection of behavior (to promote inlining rather than forcing virtual calls), and for changes to the actual structure of a class, we want compile-time elaboration. You can use some tricks to use the return type of that function at compile-time to select from an existing template specialization, but thatís worse than opening and closing namespaces, and more seriously it canít be used to pass in the type without writing helper classes, so it's not a general solution for metaprogramming.

When it is applicable, the overloaded function approach is especially handy in the way it handles derived classes. Overload it for a class and it works for all derived classes as well, implicitly. For example, previous versions of the smart pointer library used a function Get_lifetime_object (T*) during template expansion. The user could define the policy for his class by writing an overloaded version of that function along with the class. Or, if his class inherits from can_handle it would resolve the function call to Get_lifetime_object (can_handle*). Since can_handle is a mix-in designed to make the full power of the smart pointer library available efficiently, the matching function is meant for all derived classes.

Internal Type

If every class could be counted on to supply member functions (or a member policy class bundling the functions), everything would be easy! That gives compile-time and/or normal run-time polymorphism, and is easily done in the C++ language.

But there are three problems. First, without a common base class for all types T used in the template, there is no default implementation of the policy. If a generic policy worked for most classes, there should be no need to specify it in the definition of every class.

Second, it is intrusive. Well, using a mix-in is also intrusive, but the mix-in is simply one way to satisfy the requirements, and it can be done completely external to the class definition as well. So something that only works if you can tinker with the class definition is unacceptible, though if you are writing the class you could certainly include something to this end. It just has to be optional.

Finally, it doesnít work with non-class types. For class types, you could always hack the header to put in a static policy member and not affect the meaning of existing code. But for a non-class type, you canít use it directly.

On the plus side, specifying traits within the class definition is a perfectly natural thing to do. Arguably, it is indeed part of the classís behavior and should be encapsulated within it. It works smoothly in the language.

Optional Internal Traits

What I actually implemented gives the advantages of specifying policies/traits as internal to the class, but avoids the drawbacks by making it totally optional with the traditional specialization mechanism available instead, and a default that is applied if you donít do anything.

For example, consider the policy template class:

template <typename T>
class generic_policy {
public:
   static void trait1() { cout << "generic_policy is used." << endl; }
   };

The code that uses the policy is written like so:

template <typename T>
void foo (const T* p)
 {
 cout << "Type " << typeid(T).name() << " - ";
 Policy<T>::trait1();
 }

It could have been written as template <typename T, typename P=Policy<T> > if there was any need to ever pass a policy explicitly. But in my case, Iíll always use the same policy with a given class. That is why I got into the hassle of providing an explicit specialization in the first place, rather than just passing it as the optional template parameter.

Now, given a built-in type and a class that doesnít do anything special, foo invokes the generic_policy.

class C0 { int x; };

int main()
 {
 test<int>();
 test<C0>();
 }

Output:

Type int - generic_policy is used.
Type class C0 - generic_policy is used.

If a class requires something other than the generic policy, it can be specified internal to the class. It can be done (as seen below in C1) by naming the policy class policy_type and making it entirly a member of the main class, or you can make policy_type a typedef for a policy class defined elsewhere, as in C2 below.

If such a type is defined inside the class, it is used by the template.

class C1 {
public:
   class policy_type {
      public:
         static void trait1() { cout << "built-in policy is used." << endl; }
      };
   };


class D1 : public C1 {};

struct custom_policy {
      static void trait1() { cout << "custom_policy is used." << endl; }
   };

class C2 {
public:
   typedef custom_policy policy_type;
   };

int main()
 {
 test<C1>();
 test<D1>();
 test<C2>();
 }

Output:

Type class C1 - built-in policy is used.
Type class D1 - built-in policy is used.
Type class C2 - custom_policy is used.

Notice that in the above example, class D1 inherits the policy from C1.

If it is not convienient or possible to define the type internal to the class, or want it to not inherit, you can define an explicit specialization of the policy template, in the traditional manner.

class C3 { double dummy; };

template<>
class Policy<C3> : public custom_policy_2 {   };

class D3 : public C3 {};


template<>
class Policy<double> {
public:
   static void trait1() { cout << "policy for double is used." << endl; }
   };

Output:

Type class C3 - custom_policy_2 is used.
Type class D3 - generic_policy is used.
Type double - policy for double is used.

In the above example, notice that a policy is defined for the non-class type double, and that class D3 does not inherit the policy defined on its base class.

If the explicit specialization of the policy class is defined, then the policy_type name has no special meaning to the mechanism. So, if the name happens to conflict with something else in your class, you can make the problem go away.

Implementation

Here is the code used to produce this example: (or, download the full file)

template <typename T, bool internal>
class Policy_chooser;

template <typename T>
class Policy_chooser <T, true>
   {
   public:
      typedef typename T::policy_type type;
   };


template <typename T>
class Policy_chooser <T, false>
   {
   public:
      typedef generic_policy<T> type;
   };



char chooser_support_function (...);
template <typename T>
typename T::policy_type* chooser_support_function (T*);


template 
class Policy : 
   public Policy_chooser<T, 1!=sizeof(chooser_support_function((T*)0))>::type 
   {};

Notice that the last thing in the listing is the general template for Policy. If you define an explicit specialization, it is used and this generic one has no effect for that type. So, defining a specialization works in the normal manner.

Itís only when you donít define a specialization that this general one is used. Traditionally, this would implement (or point to) the generic policy. The difference here is that it looks for the internally-defined policy first.

  1. Use an explicit specialization
  2. Use an internal policy
  3. Use the generic policy

The search for an internal policy is done using the Policy_chooser template. If there is a type named T::policy_type, then the second signature is an exact match. If mentioning T::policy_type is an error, then that signature is suppressed and the other one is the only (non-overloaded) match. The template uses the difference in return type to switch between versions of the helper Policy_chooser, which brings the proper choice of generic_policy<T> or T::policy_type back to the expansion of Policy.

Reuse

Using this pattern for any given policy class is essentially boilerplate. The only thing that changes besides the name of the Policy itself is the name of the generic policy class, and the name of the policy_type internal policy indicator. The only other complication is to arrange to give the helpers unique names.

Unfortunatly, the only reuse mechanism within the C++ language that is up to this job is the preprocessor macro. You might think about putting all that stuff as member templates inside a master template, but T::policy_type will be a sticking point. How do you parameterize the name of a member type? Using another typename parameter to the template, T::R is incorrect because during template expansion R will refer to a fully-resolved type, not a relative name that can be applied to a larger identifier. This requires token pasting, hense the need for macros.