// Non-type template parameters; template template parameters;
//     combining implicit and explicit template parameters


#include "misc.h"

#include "composite.h"
#include "linked_ptr1.h"
#include "functionalobj.h"

func(f1,x+3,x);
func(g1,x*x,x);

// <done> Seriously consider making a function class, with
// a virtual function.  The compositeobj is a prime candadite
// for using it : derive a compositeobj.  Now all functions
// with the same signature could be in the same container ...
//
// make_composite<double,double>()(f,g)(2.0); is a typical
// example where I don't have its type - no handle.  It can
// be placed in code by other templates, but I can't get a list
// of these in the one container, unless they have the same
// base class, then share a common function to evaluate it - 
// this is ofcourse a virtual function.
//
// However there is an alternative here - my ranting is working.
// while its type is unknown(not by me, though the compiler knows),
// how to use it is as its a fully fledged functional object.
// By storing it in a container (templated pointer), that says
// how to evaluate it (the container could hold the virtual func,
// and let it have a base class - so can store a these in the
// same container - templated functional objects<done> 


template<class GFX, class G, class F, class X>
compositeobj<GFX,G,F,X> make_compositeobj(G g, F f, GFX , X )
{
   compositeobj< GFX, G, F, X > w(g,f);
   return w;
}

void test01()
{
   f1<double,double&,double> f;
   g1<double,double&,double> g;

   cout << SHOW( f(1.2) ) << endl;
   cout << SHOW( g(3.0) ) << endl;

   compositeobj<
      double,
      g1<double,double&,double>,
      f1<double,double&,double>,
      double > w(g,f);

   cout << w(2.0) << endl;

   // t is a dummy argument
   double t;
   cout << make_compositeobj(f,g,t,t)(2.0) << endl;

   cout << make_composite<double,double>()(f,g)(2.0) << endl;
   cout << make_composite<double,double>()(ref(f),ref(g))(2.0) << endl;

   // make a named variable, as a smart pointer it cleans up
   // The use of ref() inhibits copying of functions, instead
   // references are copied.  So f and g shouldn't die before h
   linked_ptr<functionalR1<double,double> > h( 
      make_composite<double,double>().smartptr(ref(f),ref(g)) );
   cout << (*h)(2.0) << endl;
}


//
// Non-type template parameters
//

template<int Size>
class container
{
public:
   int v[Size];

};

void test02()
{
   container<20> c;
}


//
// template template paramter : parsing a template as a parameter
//

template<class T>
class oneparam
{
public:
  T val;
  template<class U, class V>
  void eval(U& u, V& v)
  {
     val=u+v;
  }
};


template<template <typename T> class Ripoff>
class hat
{
public:

   Ripoff<int> r;
};

void test03()
{
   // oneparam is a template, requiring one argument
   hat< oneparam > x;
   x.r.val = 20;
   cout << SHOW( x.r.val ) << endl;

   double x1=3.0,x2=5.0;
   x.r.eval(x1,x1);
}

/*

class cat
{
public:
  
   template<class T>
   void eval(T& t) { cout << t << endl; }
};

class cat2
{
public:

   class objbase
   {
   public:
  
      virtual void eval()=0;
   };   

   template<class T>
   class obj : public objbase
   {
      T t;
   public:

      obj(T t_) : t(t_) {}
      void eval() { cout << t << endl; }
   };
};

class cat3 : public cat2
{
public:

   template<class W>
   class obj2 : public obj<W>
   {
   public:
   
      obj2(W t_) : obj(t_) {}
      void eval() { cout << "*" << t << "*" << endl; }
   };
};

void test04()
{
   cat c;

   char w='a';
   c.eval(w);

   cat2 c2;
   cat2::obj<char> t(w);
   t.eval();
}

*/
 
int main()
{
   test01();

   return 0;
}





