Using the C++ Math Library | ![]() ![]() |
Example Program: Passing Functions As Arguments (ex3.cpp)
This example covers advanced material. You only need to read this section if you're using a MATLAB C++ Math Library function that requires another function as an argument.
You can find the code for this example in the <matlab>/extern/examples/cppmath
directory on UNIX systems and in the <matlab>\extern\examples\cppmath
directory on PCs, where <matlab>
represents the top-level directory of your installation. See Building C++ Applications for information about building and running the example program.
Certain functions in the MATLAB C++ Math Library, for example, fmins()
and fzero()
, require user-supplied functions as arguments. fmins()
and the functions like it are called "function-functions," because they operate on functions rather than arrays. This example demonstrates how to write a function that a function-function can call.
The library supports two methods of registering your function with the MATLAB C++ Math Library: the first, and easiest, uses the feval
macros; the second requires that you write a thunk function and define and populate a local table that identifies your function for the library. The macro method performs these tasks for you.
Both methods are presented in this example. The macros support registration of the most common types of functions. You only need to use the manual, nonmacro method in certain special cases (detailed below). Read the step-by-step, nonmacro version if you want to understand in detail how the MATLAB C Math Library function mlfFeval()
executes the functions passed to it.
The MATLAB C Math Library forms the foundation for the MATLAB C++ Math Library. For the most part, the MATLAB C Math Library provides its services transparently, but there are a few places where its interface is visible.
To execute a function passed to a function-function, the C++ Math Library calls the C Math Library function mlfFeval()
. mlfFeval()
calls a thunk function that actually executes the function passed to it. That thunk function must have a C interface along with the table that identifies your function to the library. Refer to the example "Passing Functions as Arguments" in the MATLAB C Math Library User's Guide for more information on how mlfFeval()
and thunk functions work.
In this example, note the following:
fmins()
, fzero()
, and the other function-functions in the MATLAB C++ Math Library take a function name as an input argument. The function-function executes that function. The function can be one you've written or a library function.mlfFeval()
executes the functions passed to the C++ Math Library function-functions.mlfFeval()
interface into the C++ interface of a function to be executed. DECLARE_FEVAL_TABLE
macros provide an easy way to register one of your functions with the function mlfFeval()
. If you use the macros, you don't have to write a thunk function.feval
macros, you must provide a thunk function that conforms to the MATLAB C Math Library interface rather than the MATLAB C++ Math Library interface. When you write a thunk function, you must follow several guidelines. In particular, you must be careful not to delete or free any of the data passed into the function and to return a newly allocated array from the function.mxArray
structure.mxArray
pointers to functions in the MATLAB C++ Math Library or to a function you've written in C++ requires explicit conversion of the mxArray
pointers to mwArray
objects. The default conversion does the wrong thing; you must explicitly specify that the mxArray
data not be freed when the mwArray
object goes out of scope.mwArray
member function FreezeData()
modifies the mwArray
so that it does not free the mxArray
it contains. However, the function is dangerous and invites memory leaks and memory protection errors. Use it with great care, exactly as outlined in this example.Using the feval Macros
Use the feval
macros to register a function that you've written for execution by a function-function or feval()
. The macros register any function that takes a combination of 0 to 8 input arguments and 1 to 5 output arguments. If you need to register a function that takes more than 8 inputs or more than 5 outputs, you cannot use the feval
macros; you must write your own thunk function and manually construct an feval
function table.
Note
You cannot register a function that has been overloaded. In addition, the arguments to the function being registered must be of type mwArray or mwArray * , not type const mwArray& . |
The functions func1()
and main()
are the same in both versions of this example. The feval
macros replace the thunk function, a typedef
, a mlfFuncTabEnt
declaration, and the feval_init
class that you'll find in the nonmacro version.
// Example 3, macro version #include <stdlib.h> #include "matlab.hpp" // # 1 mwArray func1(mwArray x) // # 2 { // one argument test function return(times(realsqrt(x), reallog(x))); } DECLARE_FEVAL_TABLE // # 3 FEVAL_ENTRY(func1) END_FEVAL_TABLE int main(void) { try { cout << fmins("func1", 0.25) << endl; // # 4 } catch (mwException &ex) { cout << ex; } return(EXIT_SUCCESS); }
The numbered items in the list below correspond to the numbered comments in the code example:
matlab.hpp
declares the MATLAB C++ Math Library's data types and functions. matlab.hpp
includes iostream.h
, which declares the input and output streams cin
and cout
. stdlib.h
contains the definition of EXIT_SUCCESS
.
func1()
. The name of this function is subsequently passed to fmins()
. During the execution of fmins()
, control passes into the MATLAB C Math Library, which calls func1()
.
func1()
computes the natural logarithms and the square roots of the
elements in the input matrix and multiplies them together. The two
functions, reallog()
and realsqrt()
guarantee that their outputs are
noncomplex matrices, i.e., matrices that have only real (no imaginary
component) elements. Note that this computation means nothing
mathematically.
feval
macros to register func1()
as a function that can be executed by a function-function or feval()
. Begin the table with the DECLARE_FEVAL_TABLE
macro, and end the table with the END_FEVAL_TABLE
macro. Pass the func1
function pointer to the FEVAL_ENTRY
macro. The macros perform all the tasks required.
The full form of the macro is:
DECLARE_FEVAL_TABLE FEVAL_ENTRY(function_name1) FEVAL_ENTRY(function_name2) (any number of these entries...) END_FEVAL_TABLE
The macros are placed outside of all function definitions and appear after a declaration of the functions being registered.
For example,
mwArray function1(mwArray *out, mwArray x, mwArray y); mwArray function2(mwArray x); DECLARE_FEVAL_TABLE FEVAL_ENTRY(function1) FEVAL_ENTRY(function2) END_FEVAL_TABLE myfunction() { mwArray a = feval(&b, "function1", c, d); mwArray f = feval("function2", g); }
However, you do not have to register a function in the same file as the call
to the function-function or feval()
. Only one set of macros can appear in
any given source file, though you can register additional functions by using
the macros in another source file.
fmins()
from the main program, passing the string "func1"
as the first argument, and print the result. fmins()
computes a local minimizer of func1()
near its second argument, the scalar 0.25
.
feval( ) Without the Macros
The example is divided into three parts. The first part defines the function func1()
and shows the main program. The second part specifies the local feval
function table. The third part defines the thunk function. In the C++ source file, the parts would be combined in this order: func1()
, the thunk function, the feval
table code, and main()
.
// ex3.cpp #include <stdlib.h> #include "matlab.hpp" // # 1 mwArray func1(mwArray x) // # 2 { // One argument test function. return (times(realsqrt(x),reallog(x))); // # 3 } int main(void) { cout << fmins("func1",0.25) << endl; // # 4 return (EXIT_SUCCESS); }
The numbered items in the list below correspond to the numbered comments in the code example:
matlab.hpp
declares the MATLAB C++ Math Library's data types and functions. matlab.hpp
includes iostream.h
, which declares the input and output streams cin
and cout
. stdlib.h
contains the definition of EXIT_SUCCESS
.
func1()
. The name of this function is later passed to fmins()
. During the execution of fmins()
, control passes into the MATLAB C Math Library, which calls func1()
.
reallog()
and realsqrt()
, guarantee that their outputs are noncomplex matrices, i.e., matrices that have only real (no imaginary component) elements. Note that this computation means nothing mathematically.
fmins()
from the main program, passing the string "func1"
as the first argument, and print the result. fmins()
computes a local minimizer of func1()
near its second argument, the scalar 0.25
.
// This table maps string function names to function pointers. The // entries in the table are triplets: // // <string name> <user function> <thunk function> // // Every function that can be called by feval() (directly // or indirectly) must have an entry in a table like this. static mlfFuncTabEnt MFuncTab[] = // # 1 { { "func1", (mlfFuncp) func1, one_input_one_output }, // # 2 { 0, 0, 0 } // # 3 }; // The following code is a static initializer used // to initalize the feval function table. It is // intentionally outside the body of any function. class feval_init { // # 4 feval_init() { mlfFevalTableSetup( MFuncTab ); } // # 5 static feval_init feval_setup; // # 6 }; feval_init feval_init::feval_setup; // # 7
The numbered items in the list below correspond to the numbered comments in the code example:
MFuncTab[]
of type mlfFuncTabEnt
. This local function table stores one or more function table entries that identify any functions (that you've written) to be executed by a MATLAB C Math Library function-function. In this example, the table stores one entry that identifies the function that fmins()
executes, func1()
.
"func1"
,
that names the function, a pointer, (mlfFuncp)func1
, to the function itself, and a pointer, one_input_one_output
, to the thunk function that actually calls func1()
.
Notice the mlf
prefix in the names of the mlfFuncTabEnt
and mlfFuncp
types. These are types used by the MATLAB C Math Library and are used
to tell the C Math Library function mlfFeval()
about your function. For
more information on the mlfFuncTabEnt
and mlfFuncp
types, see the file
matlab.h
in the include
directory of your MATLAB installation.
{0, 0, 0}
entry.
feval_init
that will initialize the local function table.
feval_init()
. In the body of the constructor, pass your function table, MFuncTab
, to the C function mlfFevalTableSetup()
. Here is another place where the C Math Library interface is used within your C++ application.
feval_setup
of type feval_init
. The class feval_init
thus contains a static instance of itself. When you define static member data for a class, you must subsequently declare that variable in your code.
feval_setup
of type feval_init.
The syntax feval_init::feval_setup
specifies that the variable is contained within the class feval_init.
This statement is executed when static variables are initialized. Because mlfFevalTableSetup()
is called at this time by the constructor, you don't need to explicitly add your entries to the built-in function table maintained by the MATLAB C Math Library.
typedef mwArray (*PFCN_1_1)(mwArray); // # 1 // This is a "thunk function." // The thunk function serves as an interpreter // between theMATLAB C++ Math Library's internal // feval() mechanism and the user functions. // There must be one thunk function for every // combination of input and output arguments. extern "C" { // # 2 static // # 3 int one_input_one_output(mlfFuncp pFunc, int nlhs, mxArray **lhs, int nrhs, mxArray **rhs) // # 4 { mwArray Out; if ( nlhs > 1 || nrhs > 1 ) // # 5 { return(0); } mwArray tmp = mwArray( rhs[0], 0 ); // # 6 Out = (*((PFCN_1_1)pFunc))( nrhs > 0 ? tmp : mwArray::DIN); // # 7 if (nlhs > 0) { lhs[0] = Out.FreezeData(); // # 8 } return(1); // # 9 } }
The numbered items in the list below correspond to the numbered comments in the code example:
func1()
.
The typedef
statement defines a function pointer type, PFCN_1_1
, that takes
one mwArray
argument and returns an mwArray
. The name PFCN_1_1 makes
it easy to identify that the function has 1 output argument (the return) and
1 input argument. Use a similar naming scheme when you write other thunk
functions that require different numbers of arguments. For example, use
PFCN_2_3
to identify a function that has two output arguments and three
input arguments.
extern "C"
to avoid C++ name translation.
feval()
calls from other files. Note that if your application requires you to write several thunk functions, and if several of your functions are associated with each thunk function, you may want to group the thunk functions in a separate file. In that case, do not declare the thunk functions static.
func1()
. A thunk function is a translator between the interface required by the MATLAB C Math Library and your function's interface. You must use the MATLAB C Math Library's mlfFeval()
calling convention for your thunk function because mlfFeval()
calls your thunk function from within the C Math Library. Notice the arguments are of type mxArray
rather than mwArray
.
The function takes five arguments that describe any one input, one output
function (in this example the function is always func1()
): an mlfFuncp
pointer that points to func1()
, an integer (nlhs
) that indicates the number
of output arguments required by func1()
, an array of mxArray
's (lhs
) that
stores the results from func1
, an integer (nrhs
) that indicates the number of
input arguments required by func1()
, and an array of mxArray
s (rhs
) that
stores the input values. lhs
stands for the left-hand side; rhs
stands for the
right-hand side.
func1()
expects one input argument and one output argument. (The return value counts as the one output argument.) Exit the thunk function if too many input or output arguments have been provided.
mwArray
object from an mxArray*
has an optional second argument. If this argument is 1 (the default), the mwArray
destructor frees the mxArray
when its reference count reaches zero. If this argument is 0, as it is in this example, the mwArray
destructor will never free the mxArray
.
This feature allows you to convert an mxArray
to an mwArray
temporarily
without having the mwArray
object free the mxArray
when you don't want it
to. Use this feature with caution, however, because it can lead to memory
leaks; the program must free that mxArray
eventually.
func1()
, casting pFunc
, which points to func1()
, to the type PFCN_1_1
. Note that you must cast the pointer to func1()
to the function pointer type that you defined.
Verify that the expected input argument is provided. If at least one
argument is passed to the thunk function, construct an mwArray
from the
first element in the array of input values (rhs[0]
); pass that mwArray
, not
the mxArray
, as the input argument to func1()
. Otherwise, pass the special
matrix, mwArray::DIN
, that MATLAB C++ Math Library functions use to
determine the number of inputs. The return from func1()
is stored
temporarily in the local variable Out
, which is already a C++ mwArray
.
This line also demonstrates that you can call C++ routines from a C-style
function like one_input_one_output()
. Be very careful when calling C++
routines from a C routine. You must first manually convert the mxArray
arguments into mwArray
objects as demonstrated in Note 6. If you do not
convert them manually, C++ will do so automatically, with unwanted
consequences. The default mxArray
to mwArray
conversion routine assumes
that the mxArray
is freed when the last mwArray
that references it goes out
of scope. This is incorrect for matrices passed to C-style functions like
one_input_one_output()
. Failure to convert the matrices manually will
lead to memory-related bugs that are often hard to track down.
mxArray
from the mwArray
Out
returned by func1()
, and assign it to the appropriate position in the array of output values. The return value is always stored in the first position, lhs[0]
. If there were additional output arguments, values would be returned in lhs[1]
, lhs[2]
, and so on.
The thunk function calling convention requires that a C-style mxArray
be
returned rather than a C++-style mwArray
object. It is necessary to modify
the mwArray,
Out,
so that it does not free the mxArray
it contains when the
function terminates and Out
goes out of scope.
Use the mwArray
member function FreezeData()
to modify the mwArray
. Use
it very carefully. FreezeData()
violates two of the principal design
guidelines of the MATLAB C++ Math Library: it reaches into and modifies
the array upon which it is invoked, and it provides a mechanism to
circumvent the library's automatic memory management. Its effect is to
release the mxArray*
contained by the mwArray
from automatic memory
management.
FreezeData()
only works on mwArray
objects that reference mxArray*
s that
have a reference count of one. See "The Space-Time Continuum" in Chapter
7 for more details on reference counting.
Output
The program produces this output:
[ 0.13535 ]
![]() | How to Call Operators | Representing Input Arguments As a Cell Array | ![]() |