Resolving c++ function passing (as arguments to other functions) is complicated by the differences between global/static and member functions as well as by the awkward syntax. Here we attempt to provide a standardised approach to using them.
One way of standardising the approach is to utilise the idea of a function object (also known as functor). A function object is simply an object that characterises a function. In c++, this has three advantages:
An example of a unary function object is given below:
We also make a terminology distinction here when distinguishing between free and member functions. Free functions are defined to be global or static functions.
Include some or all of the following at the top of any translation unit that requires compilation of class that uses parameters.
Since it is a template class, no linking is required if you are only using this class.
Many of the higher level classes in the ecl utilise function objects, e.g. threads, signals and slots. These classes expect certain concepts to be fulfilled when accepting function objects as arguments and also make use of some of the convenience classes/tools in the above list.
Classes that accept function objects generally utilise a template parameter and require the function object to fulfill the requirements of a concept. For example, threads require function objects to satisfy the nullary function concept. The current list of concepts for function objects include:
Documentation for the concepts can be found in the ecl_concepts package.
When constructing your own function object classes to be used with higher level ecl components, they must conform to the requirements of their target concept. For example, a suitable thread class function object:
Wrapping functions can be done via construction calls to many of the classes listed above, however to make it easier, there is the overloaded
generateFunctionObject method.
A good example of its usage is with the ecl Thread class where a nullary function object is required for construction.
For member functions, in the above code we bound the instance with the member function. Alternatively, you can leave it free so that the following two lines of code produce the same result:
Threads uses the tools here, an example of thread function loading is shown below.
We only utilise at most one argument to any free/member function. In practice a limit has to be drawn somewhere and I find you can always bundle however many arguments you wish into an appropriately defined structure, so either none or one is always sufficient for all purposes.