Posts Tagged ‘method chaining’

[Edit]

When I wrote this post it was longer and more complicated than now. Thanks to Davide Di Gennaro for showing me that this approach was simpler than I thought!

[/Edit]

The curiously recurring template pattern (CRTP) is a C++ idiom in which a class X derives from a class template instantiation using X itself as template argument [Wikipedia]. Its general form is pretty easy:

template <typename T>
struct Base
{
    // ...
};

struct Derived : Base<Derived>
{
    // ...
};

Typically, this pattern is used for static polymorphism (aka, simulated dynamic binding) as well as code injectio: inside Base’s methods you can take advantage of the fact that T derives from Base, then you can static_cast the this pointer to T*:

template <typename T>
struct Base
{
    void interface()
    {
        // ...
        static_cast<T*>(this)->implementation();
        // ...
    }
};

struct Derived : Base<Derived>
{
    void implementation();
};

This short post is not about CRTP in general – for this read, for example, Wikipedia – here I’ll show how to use this pattern for polymorphic method chaining. Briefly: each method returns an object (possibly the current object itself), allowing the calls to be chained together in a single statement (a typical use – the named-parameter idiom – here “Learn how to support named parameters in C++“).

Suppose you have to write a trivial printer class looking like this:

class Printer
{
public:
      Printer(ostream& pstream) : m_stream(pstream) {}

      template <typename T>
      void print(T&& t) { m_stream << t; }

      template <typename T>
      void println(T&& t) { m_stream << t << endl; }
private:
      ostream& m_stream;
};

I’m used to be lazy and I get tired writing code like this (suppose I may not use the operator<<):

Printer printer(cout);
printer.print("Message");
printer.print(105);
printer.println(objectHavingOutOperator);

So I change a couple of things in the Printer class:

class Printer
{
public:
      Printer(ostream& pstream) : m_stream(pstream) {}

      template <typename T>
      Printer& print(T&& t) { m_stream << t; return *this; }

      template <typename T>
      Printer& println(T&& t) { m_stream << t << endl; return *this; }
private:
      ostream& m_stream;
};

Then we write:

Printer(cout).print("Message").print(105).println(objectHavingOutOperator);

Ok, that’s good but what if I create some classes deriving from Printer? Chaining is lost, isn’t it? That’s because the return type of both print and println is Printer&, ever.

A simple way to maintain the chain consists in using CRTP:

template <typename ConcretePrinter>
class Printer
{
public:
      Printer(ostream& pstream) : m_stream(pstream) {}

      template <typename T>
      ConcretePrinter& print(T&& t)
      {
          m_stream << t;
          return static_cast<ConcretePrinter&>(*this);
      }

      template <typename T>
      ConcretePrinter& println(T&& t)
      {
          m_stream << t << endl;
          return static_cast<ConcretePrinter&>(*this);
      }
private:
      ostream& m_stream;
};

class CoutPrinter : public Printer<CoutPrinter>
{
public:
     CoutPrinter() : Printer(cout) {}

     CoutPrinter& SetConsoleColor(Color c) { ... return *this; }
};

... client code ...

CoutPrinter().print("Hello ").SetConsoleColor(Color.red).println("Printer!");

This approach does not allow using a Printer class directly (sans a deriving class, due to CRTP). To evade this requirement, I suggest you to provide another base printer, like this:

class BasePrinter : public Printer<BasePrinter>
{
public:
    BasePrinter(ostream& stream) : Printer(stream) {}
};

This way you can use the Printer directly:

BasePrinter(cout).print("Hello ").println("Printer");

In general, for a longer hierarchy:

// Base class
template <typename T>
struct Base
{
 T& BaseMethod()
 {
    return static_cast<T&>(*this);
 }
};

// Inherits from Base
template <typename T>
struct Child : public Base<T>
{
 T& ChildMethod()
 {
    return static_cast<T&>(*this);
 }
};

// Inherits from Child
template <typename T>
struct ChildChild : public Child<T>
{
 ChainingReturnType& ChildChildMethod()
 {
    return static_cast<T&>(*this);
 }
};

...

Chaining works at compile-time because it uses the static type of the objects involved.

What I don’t like is the number of classes we generate to use directly all the bases: we have to define an alter-ego for each of them – and introducing a new level of indirection could be verbose:

template<typename T>
struct Base
{
   Base(...suppose some parameters...) : ... {}

   //some methods
};

struct Base_User : public Base<Base_User>
{
   Base_User(...) //...must construct Base...
   // sort of duplicated code
};

template<typename T>
struct Derived : Base<T>
{
   Derived(...suppose some parameters...) //...must construct Base & itself...

   // other methods
};

struct Derived_User : public Derived<Derived_User>
{
   Derived_User(...) //...must construct Derived...
   // sort of duplicated code
};

If you want to avoid repeating code (e.g. construction) in _User classes you can employ the idea I showed in a previous version of this post: instead of deriving from Base, Base_User is just a typedef of Base using a special type (NoCRTP) as a template parameter. This type either “enables or disables” the usage of CRTP. The code can seem complicated but it’s simpler than you think:

// trivial type-selector

template<bool, typename T, typename U>
struct select_
{
   typedef T type;
};

template<typename T, typename U>
struct select_<false, T, U>
{
   typedef U type;
};

// just a placeholder
struct NoCrtp;

// support macro
#define CRTP_TYPE(who) typename select_ < is_same<T, NoCrtp>::value, who, T>::type

// another way to realize polymorphic chaining
template<typename T>
struct Base
{
   // if (T == NoCrtp)
   //   CrtpType = Base ("disable" CRTP)
   // else
   //   CrtpType = T ("enable" CRTP)
   typedef CRTP_TYPE(Base) CrtpType;

   CrtpType& chain()
   {
      //...
      return static_cast<CrtpType&>(*this);
   }
};

typedef Base<NoCrtp> Base_User; // no duplication

template<typename T>
struct Derived : public Base<CRTP_TYPE(Derived<T>)>
{
   typedef CRTP_TYPE(Derived) CrtpType;

   CrtpType& chain_derived()
   {
     //...
    return static_cast<CrtpTyep&>(*this);
   }
};

typedef Derived<NoCrtp> Derived_User; // no duplication

...

This machinery is a bit more complicated to understand but it can avoid duplication. Choose the implementation that fits your needs.

In summary: method chaining may be elegant and useful. Its power is damped if inheritance is involved so I suggest to employ CRTP, “champion of static polymorphism” which can support method chaining, avoiding you to write lots of code. If you have more than a couple of classes your codebase may be more verbose, but don’t be afraid of this idiom, it can be a valuable ally!