C++ Explicit Functor
Jul 13, 2015
We define a c++11 class, ExplicitFunctor
, which, behaving as a functor, can evaluate arbitrary members of any class. Consider the following use of the class:
#include <iostream>
#include <cstdlib>
#include "utils/misc_wrappers.h"
class addClass {
public:
int addOneMember (int a) { return (a+1); }
};
class addFunctor {
public:
int add_amount;
addFunctor (int amount=1) : add_amount(amount) { }
int operator() (int a) { return (a+add_amount); }
int addTwoMember (int a) { return (a+2); }
};
int main(int argc, char *argv[])
{
// Use with a non-functor class
// ----------------------------
// ExplicitFunctor that creates an instance of the 'addClass'
ExplicitFunctor <addClass, int (addClass::*)(int)> addone1;
addone1.set_function_pointer (&addClass::addOneMember); // provide the member function to use
ExplicitFunctor <addClass, int (addClass::*)(int)> addone2 (NULL, &addClass::addOneMember);
// User-provided instance of the 'addClass'
addClass class_instance;
ExplicitFunctor <addClass, int (addClass::*)(int)> addone3 (&class_instance, &addClass::addOneMember);
auto addone4 = CreateExplicitFunctor (&class_instance, &addClass::addOneMember);
// Can be used with a functor class as well
// ----------------------------------------
// To use opeator()
ExplicitFunctor <addFunctor, int (addFunctor::*)(int)> addone5;
// To use a member function
ExplicitFunctor <addFunctor, int (addFunctor::*)(int)> addtwo;
addtwo.set_function_pointer (&addFunctor::addTwoMember);
// User-provided instance of the 'addFunctor'
addFunctor functor_instance(3);
ExplicitFunctor <addFunctor, int (addFunctor::*)(int)> addthree;
addthree.set_functor_instance (&functor_instance);
// -----
// All of these will print 6
std::cout << addone1(5) << std::endl;
std::cout << addone2(5) << std::endl;
std::cout << addone3(5) << std::endl;
std::cout << addone4(5) << std::endl;
std::cout << addone5(5) << std::endl;
// The following will print 7
std::cout << addtwo(5) << std::endl;
// The following will print 8
std::cout << addthree(5) << std::endl;
}
The definition of ExplicitFunctor
is as follows:
#ifndef __YAGSBPL_MISC_WRAPPERS_H
#define __YAGSBPL_MISC_WRAPPERS_H
// SFINAE for getting operator()
template <typename fun_ptr_type, fun_ptr_type fun_ptr> struct type_check;
template <typename functor_type, typename fun_ptr_type>
fun_ptr_type get_bracket_operator (type_check<fun_ptr_type, &functor_type::operator()>*)
{ return ( static_cast<fun_ptr_type>(&functor_type::operator()) ); }
template <typename functor_type, typename fun_ptr_type>
fun_ptr_type get_bracket_operator (...) { return (NULL); }
// --------------
template <class FunctorType, typename FunctionPointerType> // FunctionPointerType is a pointer type to a member function of F
class ExplicitFunctor {
/* Declaration Syntax: ExplicitFunctor <functor_class, ... (functor_class::*)(...)> ef;
Use: ef (...)
*/
private:
FunctorType* functor_instance_p;
bool new_created;
FunctionPointerType function_pointer;
public:
// function_pointer instantiation: function_pointer = &F::f
// ------------------------------------------
ExplicitFunctor () : functor_instance_p(NULL), new_created(false), function_pointer(NULL) { /*init();*/ }
ExplicitFunctor (FunctorType* in_pointer, FunctionPointerType in_func=NULL) :
functor_instance_p(NULL), new_created(false), function_pointer(NULL) { set_pointers (in_pointer, in_func); }
// check if empty
bool empty (void) { return (functor_instance_p==NULL); }
// ------------
// explicit initializations
void set_functor_instance (FunctorType* in_pointer=NULL) {
if (in_pointer) {
clear(); // clears current pointer
functor_instance_p = in_pointer;
new_created = false;
}
else if (!functor_instance_p) { // init() -- will initiate if already not initiated.
functor_instance_p = new FunctorType;
new_created = true;
}
}
void set_function_pointer (FunctionPointerType in_func=NULL) {
if (in_func)
function_pointer = in_func;
else
function_pointer = get_bracket_operator<FunctorType,FunctionPointerType>(0);
}
void set_pointers (FunctorType* in_pointer=NULL, FunctionPointerType in_func=NULL) {
set_functor_instance (in_pointer);
set_function_pointer (in_func);
}
// ------------
// operator()
template <class F>
struct return_type;
template <class R, class... A>
struct return_type <R (FunctorType::*)(A...)> {
typedef R type;
};
// forwarded
template <class... A>
typename return_type<FunctionPointerType>::type operator() (A && ... args) { // receive everything by reference
if (!functor_instance_p) set_functor_instance();
if (!function_pointer) set_function_pointer();
return ( (functor_instance_p->*function_pointer) (std::forward<A>(args)...) );
}
// ------------
// Delete / destructor
void clear (void) {
if (new_created)
delete functor_instance_p;
functor_instance_p = NULL;
new_created = false;
}
~ExplicitFunctor () {
clear();
}
};
// ----------------------
template <class FunctorType, typename FunctionPointerType>
ExplicitFunctor<FunctorType,FunctionPointerType>
CreateExplicitFunctor (FunctorType* functor_instance_p, FunctionPointerType function_pointer)
{ return (ExplicitFunctor<FunctorType,FunctionPointerType> (functor_instance_p, function_pointer)); }
#endif
#define __YAGSBPL_MISC_WRAPPERS_H
// SFINAE for getting operator()
template <typename fun_ptr_type, fun_ptr_type fun_ptr> struct type_check;
template <typename functor_type, typename fun_ptr_type>
fun_ptr_type get_bracket_operator (type_check<fun_ptr_type, &functor_type::operator()>*)
{ return ( static_cast<fun_ptr_type>(&functor_type::operator()) ); }
template <typename functor_type, typename fun_ptr_type>
fun_ptr_type get_bracket_operator (...) { return (NULL); }
// --------------
template <class FunctorType, typename FunctionPointerType> // FunctionPointerType is a pointer type to a member function of F
class ExplicitFunctor {
/* Declaration Syntax: ExplicitFunctor <functor_class, ... (functor_class::*)(...)> ef;
Use: ef (...)
*/
private:
FunctorType* functor_instance_p;
bool new_created;
FunctionPointerType function_pointer;
public:
// function_pointer instantiation: function_pointer = &F::f
// ------------------------------------------
ExplicitFunctor () : functor_instance_p(NULL), new_created(false), function_pointer(NULL) { /*init();*/ }
ExplicitFunctor (FunctorType* in_pointer, FunctionPointerType in_func=NULL) :
functor_instance_p(NULL), new_created(false), function_pointer(NULL) { set_pointers (in_pointer, in_func); }
// check if empty
bool empty (void) { return (functor_instance_p==NULL); }
// ------------
// explicit initializations
void set_functor_instance (FunctorType* in_pointer=NULL) {
if (in_pointer) {
clear(); // clears current pointer
functor_instance_p = in_pointer;
new_created = false;
}
else if (!functor_instance_p) { // init() -- will initiate if already not initiated.
functor_instance_p = new FunctorType;
new_created = true;
}
}
void set_function_pointer (FunctionPointerType in_func=NULL) {
if (in_func)
function_pointer = in_func;
else
function_pointer = get_bracket_operator<FunctorType,FunctionPointerType>(0);
}
void set_pointers (FunctorType* in_pointer=NULL, FunctionPointerType in_func=NULL) {
set_functor_instance (in_pointer);
set_function_pointer (in_func);
}
// ------------
// operator()
template <class F>
struct return_type;
template <class R, class... A>
struct return_type <R (FunctorType::*)(A...)> {
typedef R type;
};
// forwarded
template <class... A>
typename return_type<FunctionPointerType>::type operator() (A && ... args) { // receive everything by reference
if (!functor_instance_p) set_functor_instance();
if (!function_pointer) set_function_pointer();
return ( (functor_instance_p->*function_pointer) (std::forward<A>(args)...) );
}
// ------------
// Delete / destructor
void clear (void) {
if (new_created)
delete functor_instance_p;
functor_instance_p = NULL;
new_created = false;
}
~ExplicitFunctor () {
clear();
}
};
// ----------------------
template <class FunctorType, typename FunctionPointerType>
ExplicitFunctor<FunctorType,FunctionPointerType>
CreateExplicitFunctor (FunctorType* functor_instance_p, FunctionPointerType function_pointer)
{ return (ExplicitFunctor<FunctorType,FunctionPointerType> (functor_instance_p, function_pointer)); }
#endif