Functoids In Cpp With Concept Cpp

FunctoidsInCpp can be modified to use the concepts defined in ConceptCpp in place of the Sig structure to determine the return type. This code has been tested using ConceptGcc. Here are two versions of the same code, one without and one with concepts. Note that the code is not complete, e.g. both versions call through Curryable2Helper to resolve overloading of the operator() with two arguments. This call returns the type defined by the appropriate concept map. One advantage of doing it in this way is that the concept maps are reusable with different classes, rather than defined within a particular class template. -- JohnFletcher


Original Code

Version of the FunctoidsInCpp code for a two parameter polymorphic functoid not using ConceptCpp.

 template <class F>
 class Full2 : public SmartFunctoid2 {
   F f;
 public:
   Full2() : f() {}
   Full2( const F& ff ) : f(ff) {}
   template <class X, class Y=void>
   struct Sig
   : public FunType<typename F::template Sig<X,Y>::Arg1Type,
                    typename F::template Sig<X,Y>::Arg2Type,
                    typename RT<F,X,Y>::ResultType> {};
   template <class X>
   struct Sig<X,void> : public FunType<X,Full1<impl::binder1of2<F,X> > > {};
   template <class Y>
   struct Sig<AutoCurryType,Y>
   : public FunType<AutoCurryType,Y,Full1<impl::binder2of2<F,Y> > > {};
   template <class X>
   struct Sig<X,AutoCurryType>
   : public FunType<X,AutoCurryType,Full1<impl::binder1of2<F,X> > > {};
   template <class X>
   inline typename Sig<X>::ResultType 
   operator()( const X& x ) const {
     return makeFull1( impl::binder1of2<F,X>(f,x) );
   }
   template <class X, class Y>
   inline typename Sig<X,Y>::ResultType
   operator()( const X& x, const Y& y ) const {
     // need partial specialization, so defer to a class helper
     return impl::Curryable2Helper<typename Sig<X,Y>::ResultType,F,X,Y>::go(f,x,y);
   }
 };


The same code using concepts.

 auto concept ConstCallable2<typename F, typename X, typename Y = Nothing> {
  typename result_type;
  requires CopyConstructible<result_type>;
  result_type operator()(const F&, const X&, const Y& y);
 };
 /* These concept maps are the equivalent of the different Sig definitions. */
 template <class F,class X>
 concept_map ConstCallable2<F,X>
 {
  typedef Full1<impl::binder1of2<F,X> > result_type;
 };
 template <class F,class X>
 concept_map ConstCallable2<F,X,AutoCurryType>
 {
  typedef Full1<impl::binder1of2<F,X> > result_type;
 };
 template <class F,class Y>
  concept_map ConstCallable2<F,AutoCurryType,Y>
 {
  typedef Full1<impl::binder2of2<F,Y> > result_type;
 };
 template <class F>
 class Full2 : public SmartFunctoid2 {
   F f;
 public:
   Full2() : f() {}
   Full2( const F& ff ) : f(ff) {}
   template <class X>
   inline ConstCallable2<F,X>::result_type
  operator()( const X& x ) const {
     return makeFull1( impl::binder1of2<F,X>(f,x) );
   }
   template <class X, class Y>
   inline ConstCallable2<F,X,Y>::result_type
  operator()( const X& x, const Y& y ) const {
      // need partial specialization, so defer to a class helper
   return impl::Curryable2Helper<typename ConstCallable2<F,X,Y>::result_type,F,X,Y>::go(f,x,y);
  }
 };


Example of usage.

This is the code within FC++(FunctoidsInCpp) which enables code using e.g. the FC++ object minus to handle calls such as

  minus(_,1)(2); // minus(_,1) returns a function which needs another argument.
  minus(2,_)(1); // minus(2,_) returns a function which needs another argument.
which need to be distinguished at compile time from

  minus(2,1);  // returns a result
where the _ character is an object of type AutoCurryType. Both versions of the code use the type of the argument to guide the selection of the return type from the two argument call. The actual return types are constructed in template specialisations of Curryable2Helper which are not shown here. They are the same whether or not concepts are used.

Single parameter calls can also be used

   minus(2)(1);  // minus(2) returns a function which needs another argument.
In this case the concept map has one template parameter and the other is supplied by the default type Nothing.

-- JohnFletcher


CategoryCpp CategoryCppTemplates CategoryFunctionalProgramming CategoryConcepts


EditText of this page (last edited May 22, 2009) or FindPage with title or text search