fuseinabowl
fuseinabowl

Reputation: 67

What is this pattern's name?

I have written a few template classes as part of a larger template class. One allows me to include or exclude member variables from a class. Another allows me to produce either the passed template class parameter or a placeholder that NOPs instead.

These allow classes to use their own template parameters to include or exclude data members through a single very generic class definition, and the operations provide an interface that prevents type mismatch issues.

This code sample shows my implementation in use as I assume it will be easier to recognise in action (the classes relating to the pattern have been called "ghost").

typedef int field1type, field2type, field3type;

template <bool field1exists, bool field2exists, bool field3exists>
struct GhostShowcase
{
  typename Ghost<int, field1exists>::type intField;
  typename Ghost<float, field2exists>::type floatField;
  typename Ghost<char, field3exists>::type charField;
};

GhostShowcase<true,false,true> foo; // has int and char fields
                                    // but an unusable float field
GhostShowcase<true,true,true> bar; // has all fields usable

The samples below show how to use operators with the types derived from ghost classes. The testing function printAll() uses ghostStaticOperator() to call static functions in a class derived from GhostStaticOperation. This class is either the class that was passed as a template parameter to GhostStaticOperation or an automatically generated class which has a static function with the same signature but does nothing. The class chosen is based on the boolean template parameter exists. in main() two calls are made; the first passes the template parameter true and the second passes false.

These samples show compilable source (in g++ 4.5.2, with -std=c++0x set). This file can be named anything.

#include "ghost.h"
#include <iostream>
#include <functional>

using namespace Aryana;
using namespace std;

struct PrintingOperator : public std::unary_function<int, void>
{
  static inline void operation(int toPrint)
  {cout << toPrint;}
};

struct IncrementOperator : public std::unary_function<int&, void>
{
  static inline void operation(int& toIncrement)
  {++toIncrement;}
};

template <bool exists>
void printAll()
{
  typedef GhostStaticOperator<PrintingOperator, exists> printClass;
  typedef GhostStaticOperator<IncrementOperator, exists> incrClass;

  typename Ghost<int, exists>::type ghostObject;
  cout << "using ghost printer: ";
  ghostStaticOperation<printClass>(ghostObject);
  cout << "\nusing ghost incrementor...\n";
  ghostStaticOperation<incrClass>(ghostObject);
  cout << "using ghost printer: ";
  ghostStaticOperation<printClass>(ghostObject);
  cout << "\nfinished\n";
}

int main(int, char**)
{
  cout << "ghost operation with exists=true:\n";
  printAll<true>();
  cout << "ghost operation with exists=false:\n";
  printAll<false>();
}

This sample should be named "ghost.h" and put in the same directory as the previous file.

typedef char ghost_null_argument[0];
typedef void ghost_null_return;

template <class S, bool exists>
class Ghost;

template <class S, bool exists>
class GhostOperator;

template <class S, bool exists>
class GhostStaticOperator;

template <class S>
class Ghost<S, false>
{
  Ghost(); // private constructor to prevent instantiation
 public:
  typedef ghost_null_argument type;
  typedef S original_type;
};

template <class S>
class Ghost<S, true>
{
  Ghost(); // private constructor to prevent instantiation
 public:
  typedef S type;
  typedef S original_type;
};

template <class S, bool exists>
class GhostOperator;

template <class S>
class GhostStaticOperator<S, false>
{
  GhostStaticOperator(); // private constructor to prevent instantiation
 public:
  typedef ghost_null_return result_type;
  typedef ghost_null_argument argument_type;
  struct operator_type
  {
    inline static result_type operation(argument_type){};
  };
};

template <class S>
class GhostStaticOperator<S, true>
{
  GhostStaticOperator(); // private constructor to prevent instantiation
 public:
  typedef S operator_type;
  typedef typename operator_type::result_type result_type;
  typedef typename operator_type::argument_type argument_type;
};

// must define argument_type and result_type in the operator class
// result_type will be ghost_null_argument if the class is ghosting
template <class S>
inline
typename S::result_type ghostStaticOperation(typename S::argument_type argument)
{
  return S::operator_type::operation(argument);
}

Upvotes: 0

Views: 293

Answers (1)

MSalters
MSalters

Reputation: 179981

I'm fairly certain it's the "bug" pattern. char[0] is not a valid member type.

More seriously, normally we use SFINAE to directly check for members that might or might not exist. That avoids the whole Ghost<T, bool> template.

Upvotes: 1

Related Questions