Compile Time Indirection - An Unusual Template Technique

Compile Time Indirection - An Unusual Template Technique

By Alan Griffiths

Overload, 9(42):, April 2001


It is a common idiom in C++ to write a class whose sole data member is a pointer to another class that provides the implementation. Originally called "The Cheshire Cat Idiom" this has more recently been dubbed "Compilation Firewall" and "The Pimpl Idiom". This last comes from the following paradigm:

// Header file
class interface {
  /* omitted */
private:
  class impl;
  impl* pimpl;  
} ;
// Implementation file
class interface::impl {
  /* omitted */
} ;

However, this is all by way on a preamble - since the situation I want to address is motivated less by implementation hiding and more by the desire to provide a variable implementation. For example. we may want to vary between implementations state1 , state2 and state3 at run time. (As the names suggest this is one reasonable way to implement state machines.)

The only difficulty with this is that we can't write:

class state1 : public interface::impl {
...

because interface::impl is inaccessible.

There are two obvious approaches to resolving this inaccessibility issue. Both of these are inelegant because implementation details become exposed in the header file.

The first solution is to make impl a public member of interface . Making impl public pollutes the client interface:

// Header file
class interface {
  /* omitted */
  class impl;
private:
  impl* pimpl;  
} ;
// Implementation file
class interface::impl {
  /* omitted */
} ;
// . . .
class state1 : public interface::impl {
  /* omitted */
} ;

The second approach is to forward declare state1 (and kin) and make them friends. This exposes even more of the implementation details in the header file:

// Header file
class state1;
class interface {
  /* omitted */
private:
  friend state1;
  class impl;
  impl* pimpl;  
} ;
// Implementation file
class interface::impl {
  /* omitted */
} ;
// . . .
class state1 : public interface::impl {
  /* omitted */
} ;

Neither approach is a disaster, but the inelegance niggled at me until I realised there was a third solution that retains the original form of the header file:

// Header file
class interface {
  /* omitted */
private:
  class impl;
  impl* pimpl;  
} ;
// Implementation file
class interface::impl {
  /* omitted */
} ;
// . . .
template<class impl>
class state1 : public impl {
/* omitted */
} ;
// . . .
interface::interface(): pimpl(new state1<impl>)
// . . .

This works because interface has access to impl and can use it as a template parameter and because state1<> has access to its template parameter.

In C++ the template mechanisms are most commonly used to support genericity. The technique illustrated here is unusual in that it uses them instead to promote encapsulation.






Your Privacy

By clicking "Accept Non-Essential Cookies" you agree ACCU can store non-essential cookies on your device and disclose information in accordance with our Privacy Policy and Cookie Policy.

Current Setting: Non-Essential Cookies REJECTED


By clicking "Include Third Party Content" you agree ACCU can forward your IP address to third-party sites (such as YouTube) to enhance the information presented on this site, and that third-party sites may store cookies on your device.

Current Setting: Third Party Content EXCLUDED



Settings can be changed at any time from the Cookie Policy page.