// See http://www.dlugosz.com/Repertoire/refman/techniques/internal_policies.html

#include <iostream>
#include <typeinfo>
using std::endl;
using std::cout;


template <typename T>
class generic_policy {
public:
   static void trait1() { cout << "generic_policy is used." << endl; }
   };

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 <typename T>
class Policy : 
   public Policy_chooser<T, 1!=sizeof(chooser_support_function((T*)0))>::type 
   {};

////////////////////



template <typename T>
void foo (const T* p)
 {
 cout << "Type " << typeid(T).name() << " - ";
 Policy<T>::trait1();
 }


class C0 { int x; };


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; }
   };


struct custom_policy_2 {
      static void trait1() { cout << "custom_policy_2 is used." << endl; }
   };

class C2 {
public:
   typedef custom_policy policy_type;
   };


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; }
   };


template <typename T>
void test()
 {
 T x;
 foo (&x);
 }

int main()
 {
 cout << "Running." << endl;
 test<int>();
 test<C0>();
 test<C1>();
 test<D1>();
 test<C2>();
 test<C3>();
 test<D3>();
 test<double>();
 }

