// -*- mode:C++ -*-

//////////////////////////////////////////////////////////////////////
// Named "function" parameters
//////////////////////////////////////////////////////////////////////

class named_fn 
{
  int _id;
  double _val;
  int _dim;
  
  public:
  named_fn() : _id(0), _val(1), _dim(2) {}
  named_fn& id(int p)     { _id  = p ; return *this; }
  named_fn& val(double p) { _val = p ; return *this; }
  named_fn& dim(int p)    { _dim = p ; return *this; }

  ~named_fn() {
    //Itt van maga az algoritmus
  }
};

//Hasznalat:
//named_fn().id(3);
//named_fn().id(3).val(2);
//named_fn().dim(4).id(3);


//////////////////////////////////////////////////////////////////////
// Named class template parameters (A)
//////////////////////////////////////////////////////////////////////

template<class A=int,class B=double>
class Named_T
{
public:

  typedef A Atype;
  typedef B Btype;

  template <class T> class SetAType : public Named_T<T,Btype> { };
  template <class T> class SetBType : public Named_T<Atype,T> { };
};

// Named_T<>::SetAType<double>::SetBType<double>

//////////////////////////////////////////////////////////////////////
// Named class template parameters (A)
//////////////////////////////////////////////////////////////////////

struct _NTR 
{
  typedef int Atype;
  typedef double Btype;
};

template<class TR=_NTR>
class Named_TR
{
public:

  typedef typename TR::Atype Atype;
  typedef typename TR::Btype Btype;

  Atype a;
  Btype b;
  
  template <class T>
  struct ATR : public TR {
    typedef T Atype;
  };

  template <class T>
  class SetAType : public Named_TR<ATR<T> > { };

  template <class T>
  struct BTR : public TR {
    typedef T Btype;
  };
  template <class T>
  class SetBType : public Named_TR<BTR<T> > { };

  Named_TR() {};
  Named_TR<TR> &setA(Atype _a) { a=_a; return *this;}
  Named_TR<TR> &setB(Btype _b) { b=_b; return *this;}

  void run() {
    // itt az algoritmus
  }

  //////////////////////////////////////////////////////////////////////
  template<class T>
  SetAType<T> SETA(T t) { SetAType<T> r; r.a=t; r.b=b; return r;}
  template<class T>
  SetBType<T> SETB(T t) { SetBType<T> r; r.a=a; r.b=t; return r;}
};

// Hasznalat:
// 1.
//   Named_TR<>::SetAType<double> nt;
//   Named_TR<>::SetBType<double>::SetAType<double> nt2;
//   nt2.setA(5).setB(6).run();
// 2.
//   double x;
//   Named_TR<>().SETA(5.2).SETB(x).run();
// 3. 
//   struct MyTr : public _NTR { typedef float Btype; };
//   int main() 
//   {
//     Named_TR<MyTr> d2; d2=d2;
//   }


// Sajnos ezt csak a fuggvenyen kivul lehet deklaralni:
struct MyTr : public _NTR { typedef float Btype; };

typedef Named_T<> Named_TN;

int main()
{

  Named_T<> a;a=a;
  Named_T<>::SetAType<double> b;b=b;
  Named_T<>::SetAType<double>::SetBType<int> c;c=c;

  Named_TR<> a2;a2=a2;
  Named_TR<>::SetAType<double> b2;b2=b2;
  Named_TR<>::SetAType<double>::SetBType<int> c2;c2=c2;

  //De igy is lehet:
  Named_TR<MyTr> d2; d2=d2;

  named_fn().id(3);
  named_fn().id(3).val(2);
  named_fn().dim(4).id(3);

   Named_TR<>::SetAType<double> nt;
   Named_TR<>::SetBType<double>::SetAType<double> nt2;
   nt2.setA(5).setB(6).run();

   double x;
   Named_TR<>().SETA(5.2).SETB(x).run();
}

