diff --git a/pub/lib/func.cpp b/pub/lib/func.cpp
index e1dcea4f206af4074918541865f58e9ff372d5ae..81242db15046c9cbf91c6bb00a3d8badeb99df8f 100644
--- a/pub/lib/func.cpp
+++ b/pub/lib/func.cpp
@@ -316,36 +316,36 @@ double func_rotdiff( double w, double tau, double qb )
 //*  Coordinate concatenation                                            
 //**************************************************************************************************
 
-CCoord CFunc1::coord( CCoord *co1 ) const
+CCoord CFunc::coord( CCoord *co1 ) const
 {
     CCoord co = *co1;
-    if (txt=="0-") {
+    if        (tag=="0-") {
         co.name = "-" + co1->name;
-    } else if (txt=="ln") {
+    } else if (tag=="ln") {
         co.name = "ln " + co1->name;
-    } else if (txt=="lg") {
+    } else if (tag=="lg") {
         co.name = "lg " + co1->name;
-    } else if (txt=="sqrt") {
+    } else if (tag=="sqrt") {
         co.name = "sqrt (" + co1->name + ")";
         co.unit = co1->unit=="" ? "" : "(" + co1->unit + ")^1/2";
     } else {
-        co.name = txt + "(" + co1->name + ")";        
+        co.name = tag + "(" + co1->name + ")";        
     }
     return co;
 }
 
-CCoord CFunc2::coord( class CCoord *co1, class CCoord *co2 ) const
+CCoord CFunc::coord( class CCoord *co1, class CCoord *co2 ) const
 {
     CCoord co = *co1;
 
-    if ( txt=="+" || txt=="-" ) {
+    if ( tag=="+" || tag=="-" ) {
         if( co1->name==co2->name ){
             if( co1->unit!=co2->unit )
                 throw "same coordinate name and different units" 
                     " in additive operation";
             co = *co1;
         } else {
-            co.name = co1->name + txt + co2->name;
+            co.name = co1->name + tag + co2->name;
             if ( co1->unit=="" )
                 co.unit = "";
             else if ( co2->unit!="" && co2->unit!=co1->unit) {
@@ -355,34 +355,34 @@ CCoord CFunc2::coord( class CCoord *co1, class CCoord *co2 ) const
             } else
                 co.unit = co1->unit;
         }
-    } else if ( txt=="*" || txt=="/" ) {
-        co.name = co1->name + txt + co2->name;
+    } else if ( tag=="*" || tag=="/" ) {
+        co.name = co1->name + tag + co2->name;
         if     ( co1->unit!="" && co2->unit!="" )
-            co.unit = co1->unit + txt + co2->unit;
+            co.unit = co1->unit + tag + co2->unit;
         else if( co1->unit!="" )
             co.unit = co1->unit;
         else if( co2->unit!="" )
-            co.unit = txt=="*" ? co2->unit : "1/(" + co2->unit + ")";
+            co.unit = tag=="*" ? co2->unit : "1/(" + co2->unit + ")";
         else
             co.unit = "";
-    } else if ( txt=="^" ) {
+    } else if ( tag=="^" ) {
         if (co2->unit != "") {
             cout << "? exponent is not dimensionless\n";
         }
         co.name = co1->name + "^" + co2->name;
         co.unit = co1->unit=="" ? "" : ( co1->unit + "^<val>" );
     } else {
-        co.name = txt + "(" + co1->name + "," + co2->name + ")";
+        co.name = tag + "(" + co1->name + "," + co2->name + ")";
         co.unit = "";
     }
     return co;
 }
 
-CCoord CFunc3::coord( class CCoord *co1, class CCoord *co2, class CCoord *co3 )
+CCoord CFunc::coord( class CCoord *co1, class CCoord *co2, class CCoord *co3 )
     const
 {
     CCoord co;
-    co.name = txt + "(" + co1->name + "," + co2->name + "," + co3->name + ")";
+    co.name = tag + "(" + co1->name + "," + co2->name + "," + co3->name + ")";
     co.unit = "";
     return co;
 }
@@ -393,14 +393,14 @@ CCoord CFunc3::coord( class CCoord *co1, class CCoord *co2, class CCoord *co3 )
 //**************************************************************************************************
 
 namespace NFunctions { // internals:
-    map<const char*,const CFunc*> fmap; // unsorted hash, for expression evaluation
-    vector<const CFunc*> flist;    // sorted array, for help text
+    map<string,CFunc*> FMap; // unsorted hash, for expression evaluation
+    vector<const CFunc*> FList;    // sorted array, for help text
 }
 
-const CFunc* NFunctions::find( string key )
+const CFunc* NFunctions::find( string tag )
 {
-    auto pos = fmap.find(key);
-    return pos == fmap.end() ? NULL : pos->second;
+    auto pos = FMap.find(tag);
+    return pos == FMap.end() ? NULL : pos->second;
 }
 
 void NFunctions::display_functions()
@@ -409,60 +409,64 @@ void NFunctions::display_functions()
     // first operators by precedence, then functions.
 
     cout << "Operators by precedence:\n";
-    int prec = -1;
-    for( int i=0; i<flist.size(); ++i ){
+    int precedence = -1;
+    for( int i=0; i<FList.size(); ++i ){
         const CFunc *f;
-        f = flist[i];
-        if( f->prec ) { // operators
-            if( f->prec!=prec )
+        f = FList[i];
+        if( f->precedence ) { // operators
+            if( f->precedence!=precedence )
                 cout << "\n ";
-            cout << " " << f->txt;
+            cout << " " << f->tag;
         } else { // functions
-            if( f->prec!=prec )
+            if( f->precedence!=precedence )
                 cout << "\nBuilt-in functions:\n";
-            cout << "  " << f->txt << f->com << "\n";
+            cout << "  " << f->tag << f->explanation << "\n";
             }
-        prec = f->prec;
+        precedence = f->precedence;
     }
 }
 
-void register_fct_meta( const char* _name, int _narg, const char* _explanation, int _precedence )
+void register_fct_template( const char* _tag,
+                            const char* _outtype, const char* _intypes, void* _f )
 {
-    CFunc* f;
-    if      ( _narg==1 )
-        f = new CFunc1( _name, _explanation, _precedence );
-    else if ( _narg==2 )
-        f = new CFunc2( _name, _explanation, _precedence );
-    else if ( _narg==3 )
-        f = new CFunc3( _name, _explanation, _precedence );
-    else
-        throw S("invalid _narg");
-    
-    NFunctions::fmap.insert( make_pair( _name, f ) );
-    NFunctions::flist.push_back( f );
+    auto pos = NFunctions::FMap.find(_tag);
+    if( pos != NFunctions::FMap.end() )
+        throw S("Cannot register fct_") + _outtype + "_" + _intypes + "_" + _tag +
+            ": no meta entry";
+    const auto tf = new CTypedFunc( _outtype, _intypes, _f );
+    pos->second->tyfulis.push_back( tf );
+}
+
+void register_fct_meta( const char* _tag, int _narg, const char* _explanation, int _precedence )
+{
+    CFunc* f( new CFunc( _tag, _narg, _explanation, _precedence ) );
+    NFunctions::FMap.insert( make_pair( _tag, f ) );
+    NFunctions::FList.push_back( f );
 }
 
-void register_fct_i_i( const char* _name, func_i_i _f )
+void register_fct_i_i( const char* _tag, func_i_i _f )
 {
+    register_fct_template( _tag, "i", "i", (void*)_f );
 }
 
-void register_fct_d_d( const char* _name, func_d_d _f )
+void register_fct_d_d( const char* _tag, func_d_d _f )
 {
+    register_fct_template( _tag, "d", "d", (void*)_f );
 }
 
-void register_fct_e_e( const char* _name, func_e_e _f )
+void register_fct_e_e( const char* _tag, func_e_e _f )
 {
 }
 
-void register_fct_i_i_i( const char* _name, func_i_i_i _f )
+void register_fct_i_i_i( const char* _tag, func_i_i_i _f )
 {
 }
 
-void register_fct_d_d_d( const char* _name, func_d_d_d _f )
+void register_fct_d_d_d( const char* _tag, func_d_d_d _f )
 {
 }
 
-void register_fct_e_e_e( const char* _name, func_e_e_e _f )
+void register_fct_e_e_e( const char* _tag, func_e_e_e _f )
 {
 }
 
diff --git a/pub/lib/func.hpp b/pub/lib/func.hpp
index fd441f9d8e64908a6a50147feb939aae2229d86d..c50b636a5776b054ea94315916fd1b3cb5640412 100644
--- a/pub/lib/func.hpp
+++ b/pub/lib/func.hpp
@@ -32,51 +32,31 @@ typedef void (*deri_f2) (double&,double&,double,double,double,double);
 typedef void (*deri_f3) (double&,double&,
                          double,double,double,double,double,double);
 
-//! A wrapper holding a function, its gradient, its name, and more.
+//! A wrapper holding a function with given input and output types.
+
+class CTypedFunc {
+ public:
+    const string outtype;
+    const string intypes;
+    void* f; // the polymorphic function pointer
+    CTypedFunc( const char* _outtype, const char* _intypes, void* _f )
+        : outtype(_outtype), intypes(_intypes), f(_f) {};
+};
+    
+//! A wrapper holding a function.
 
 class CFunc {
  public:
-    const char* name;
+    const string tag;
     int narg;
     const char* explanation;
     int precedence;
-    CFunc( const char* _name, int _narg, const char* _explanation="", int _precedence )
-        : name(_name), narg(_narg), explanation(_explanation), precedence(_precedence) {};
-    virtual ~CFunc() {}; // magic: makes dynamic_cast possible
-};
-
-//! Wrapping a function with 1 argument.
-
-class CFunc1 : public CFunc {
- public:
-    func_f1 f1;
-    deri_f1 d1;
-    CFunc1( const char* _name, const char* _explanation="", int _precedence ) :
-        : CFunc( _name, 1, _explanation, _precedence ) {};
+    vector<const CTypedFunc*> tyfulis; //! List of available typed function instances.
+    CFunc( const char* _tag, int _narg, const char* _explanation, int _precedence=0 )
+        : tag(_tag), narg(_narg), explanation(_explanation), precedence(_precedence) {};
     class CCoord coord( class CCoord *co ) const;
-};
-
-//! Wrapping a function with 2 arguments.
-
-class CFunc2 : public CFunc {
- public:
-    func_f2 f2;
-    deri_f2 d2;
-    CFunc12( const char* _name, const char* _explanation="", int _precedence ) :
-        : CFunc( _name, 2, _explanation, _precedence ) {};
     class CCoord coord( class CCoord *co1, class CCoord *co2 ) const;
-};
-
-//! Wrapping a function with 3 arguments.
-
-class CFunc3 : public CFunc {
- public:
-    func_f3 f3;
-    deri_f3 d3;
-    CFunc3( const char* _name, const char* _explanation="", int _precedence ) :
-        : CFunc( _name, 3, _explanation, _precedence ) {};
-    class CCoord coord(
-        class CCoord *co1, class CCoord *co2, class CCoord *co3 ) const;
+    class CCoord coord( class CCoord *co1, class CCoord *co2, class CCoord *co3 ) const;
 };
 
 //! Collection of function wrappers CFunc
diff --git a/pub/lib/node.cpp b/pub/lib/node.cpp
index ac1dccb7ffd50d109eca469f77ed75be17421ab9..1fcbd511deede4bab01c7cf4314c8c6b35583525 100644
--- a/pub/lib/node.cpp
+++ b/pub/lib/node.cpp
@@ -255,20 +255,20 @@ void CNodeFun::npar_exec( int *np ) const
 void CNodeFun1::set_coord( CCoord& ret, int k ) const {
     CCoord r;
     arg[0]->set_coord( r, k );
-    ret = (dynamic_cast<const CFunc1*>( fu ))->coord( &r );
+    ret = fu->coord( &r );
 }
 void CNodeFun2::set_coord( CCoord& ret, int k ) const {
     CCoord r[2];
     arg[0]->set_coord( r[0], k );
     arg[1]->set_coord( r[1], k );
-    ret = (dynamic_cast<const CFunc2*>( fu ))->coord( r+0, r+1 );
+    ret = fu->coord( r+0, r+1 );
 }
 void CNodeFun3::set_coord( CCoord& ret, int k ) const {
     CCoord r[3];
     arg[0]->set_coord( r[0], k );
     arg[1]->set_coord( r[1], k );
     arg[2]->set_coord( r[2], k );
-    ret = (dynamic_cast<const CFunc3*>( fu ))->coord( r+0, r+1, r+2 );
+    ret = fu->coord( r+0, r+1, r+2 );
 }
 
 //! Returns string representation of this node.