Local Function Emulation

  • Header: cxxomfort/extras/localfn.hpp .
  • Macro: If enabled, CXXOMFORT_USING_LOCALFN is defined.

One of the big limitations of C++03 when using algorithms is that local types in a scope can not be used as arguments of templates. This means that functors declared locally can not be used with eg.: std::accumulate. C++11 gets rid of that misfeature (and even if it didn't it provides lambdas, which solve the issue).

This has led to the belief that local functors are not usable in C++03 when in fact they are, for a certain definition of "local". This header, and other libraries such as Boost.LocalFunction, adds an idiom that enabled locally-defined functors to be used in algorithm calls.

The headers adds dual macro that specify the signature and name of a local function. The user then adds the body of code of the functor in between, in a way similar as adding the body of code of a lambda in C++11. The macro CXXO_LOCALFN(signature) creates a "local" functor with a specified signature, then follows its argument list and body of code, then the macro CXXO_LOCALFN_NAME(name) creates a variable of name name tied to it.

// here, X is a tag that identifies the functor type in case one needs to add state or other nontrivial behaviour
CXXO_LOCALFN(X,void(int,int)) (int x0, int x1) {
    std::cout<< '{'<< x0+1<< ','<< x1-1<< '}'<< std::endl;
} 
CXXO_LOCALFN_NAME(X,mi_fn);
function<void(int,int)> f_localfn = mi_fn;

CXXO_LOCALFN( Neg_, int(int) ) (int x) {
    return -x;
    }
CXXO_LOCALFN_NAME(Neg_, negate);
transform( begin(sequence), end(sequence), begin(sequence), negate );

In C++11 onwards mode, this dual macro expands to a small, anonymous functor struct with zero run-time overhead. It is no different from a lambda except for the fact that its constitution as a struct with a member function is named.

In C++03 mode, this feature incurs in the overhead of a virtual function call (thus might incur in two virtual function calls if the object is stored in a std::function).

Accessing outer scope state

Note that in C++03 mode local functor classes, using this library or not, can not access normal variables in their parent scope; they only have access to const and, for write, static variables. If you need your functor to write state from its parent scope, the portable way to do it is to declare the variable as static.

It is possible to bind normal variables from outer scope for write, but that requires some setup:

  • Pass the type declaration of the variables you want to bind, converting them to references, to the CXXO_LOCALFN call.
  • Write a constructor statement passing references to set up the binders, and follow it with CXXO_LOCALFN_INIT.
  • Add the list of variables to bind to the constructor call in CXXO_LOCALFN_NAME.

(Example to be posted).

Requirements:

  • In C++03 mode, adequate support for std::result_of (from Tr1's <functional>) is required.
  • In C++03, if using the non-tag version (CXXO_LOCALFN0), requires a __typeof__ intrinsic like GCC's to work.