Boost logo

Boost :

Subject: [boost] [local_function] passing local functions as template parameters
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2010-09-12 11:41:29


Hello all,

Can you please check if the following mechanism can be used to pass
local functor classes as template parameters?

PROBLEM

If I understand the C++ standard right, local classes cannot be passed
as template parameters. Because of that, if I am defining a functor to
pass to `std::for_each` I have to define it outside the local scope,
far from the `for_each` call, which is not ideal (from cplusplus.com):

struct myclass {
  void operator() (int i) {cout << " " << i;}
} myobject;

int main () {
  // Ideally `myclass` would be defined here locally...

  vector<int> myvector;
  myvector.push_back(10);
  myvector.push_back(20);
  myvector.push_back(30);

  cout << "\nmyvector contains:";
  for_each (myvector.begin(), myvector.end(), myobject);
  cout << endl;

  return 0;
}

The code above does not compile on GCC if `myclass` is defined locally
within `main`'s scope (it still compiles on MSVC instead...).

SOLUTION (?)

The following mechanism allows to define the functor body locally (in
a local function which also binds the in-scope parameter `x`) and then
pass it as a template parameter (to `boost::bind()` and then to
`std::for_each()`). The trick is for the local function to override
the virtual body of a global class and then pass the local function as
a pointer to the global class while dynamic binding will actually
execute the locally overridden body code.

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <algorithm>
#include <vector>

template<typename F> struct lfn_global {};
template<typename A1> struct lfn_global<void (A1)> { virtual void body(A1) {} };
// Similarly define `lfn_global` for other function arities and return types.

int main () {
    double x = 5.6;

    struct lfn_t: lfn_global<void (int)> {
        lfn_t(double const& bound_x): x(bound_x) {}
        void body(int i) {
            std::cout << " " << i + x; // Local func body.
        }
    private:
        double const& x;
    } lfn_obj(x); // x is const& bound from scope.
    boost::function<void (int)> lfn = boost::bind(
            &lfn_global<void (int)>::body,
            (lfn_global<void (int)>*)(&lfn_obj),
            _1);

    std::vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);

    std::cout << "v: ";
    std::for_each(v.begin(), v.end(), lfn); // I can pass the local functor!
    std::cout << std::endl;

    return 0;
}

This code compiles on both GCC and MSVC, it correctly prints "v: 15.6
25.6 35.6". If this indeed works, I can hide all the extra code it
requires behind the `BOOST_LOCAL_FUNCTION...` macros.

Can you please try this code on other compilers? Do you see any issue
with this code?

Thank you very much.

--
Lorenzo

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk