7

What construct should be used as surrogate for std::function<> when C++11 is not available ?
The alternative should basically allow to access private member functions of one class from another class like in the example below (other features of std::function are not used). Class Foo is fixed and can not be changed much, I have only access to class Bar.

class Foo {
  friend class Bar; // added by me, rest of the class is fixed
  private:

  void doStuffFooA(int i);
  void doStuffFooB(int i);
};

class Bar {
  public:

  Bar( Foo foo, std::function< void (const Foo&, int) > func ) {
    myFoo = foo;
    myFooFunc = func;
  };

  private:

  doStuffBar( const &Foo foo ) {
    myFooFunc( foo, 3 );
  }

  Foo myFoo;
  std::function< void (const Foo&, int) > myFooFunc;
}

int main() {

  Foo foo(...);

  Bar barA( foo, &Foo::doStuffFooA );

  Bar barB( foo, &Foo::doStuffFooB );
  ...
}
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
andrsmllr
  • 1,231
  • 18
  • 39
  • 1
    This code shouldn't compile, even when the obvious syntactic errors are fixed. The two `Bar` objects are constructed with pointers to private member functions, but the code where this occurs does not have access to those members. This has nothing to do with `std::function`; it doesn't get to break access rules. – Pete Becker Mar 02 '13 at 17:37

1 Answers1

10

Is there something similar to std::function before C++11?

Yes. There is Boost.Function (boost::function<>), which lately became part of the C++ Standard Library and provided a reference implementation for std::function<> ; similarly, Boost.Bind (boost::bind<>()) was adopted by the Standard and became std::bind<>().

It implements a technique called type erasure for holding callable objects of any type. Here is a possible, illustrative implementation of how such a class template could be defined from scratch (do not use in production code, this is just an example):

#include <memory>

template<typename T>
struct fxn { };

template<typename R, typename... Args>
struct fxn<R(Args...)>
{

public:

    template<typename F>
    fxn(F&& f) 
        : 
        _holder(new holder<typename std::decay<F>::type>(std::forward<F>(f)))
    { }

    R operator () (Args&&... args)
    { _holder->call(std::forward<Args>(args)...); }

private:

    struct holder_base
    { virtual R call(Args&&... args) = 0; };

    template<typename F>
    struct holder : holder_base
    {
        holder(F&& f) : _f(std::forward<F>(f)) { }
        R call(Args&&... args) { return _f(std::forward<Args>(args)...); }
        F _f;
    };

    std::unique_ptr<holder_base> _holder;
};

#include <iostream>

int main()
{
    fxn<void()> f = [] { std::cout << "hello"; };
    f();
}
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • Indeed, a lot of features from boost can be seen as "pre-standard". – leemes Mar 02 '13 at 14:49
  • Nice code which shows how we can build this from scratch, but you have to keep in mind that this is C++11. ;) I guess the boost implementation is far more complicated (I guess they use their preprocessor library for that?) – leemes Mar 02 '13 at 14:53
  • @leemes: Yes, of course. I just wanted to provide an insight on what the implementation principle is, more or less. This is not only C++11, but also very rudimental. – Andy Prowl Mar 02 '13 at 14:57
  • 3
    Iirc `function` is also available in tr1 which was implemented in most standard libraries well before c++11 and again is almost identical to `boost::function`. – John5342 Mar 02 '13 at 14:59
  • 1
    @leemes I like to think of Boost as `avant-garde`... "pre-standard" makes me think of K&R C `;-)`. – rubenvb Mar 02 '13 at 15:24
  • 1
    @rubenvb: Yes, and there is also the fact that some changes are made on the Boost libraries during the process of their incorporation. Boost is kind of a sandbox for experimentation, and even though its libraries are of high-quality there are sometimes pain points that are only identified once released in the wild... and those can be culled/reworked before Standard integration to get an even better standard. – Matthieu M. Mar 02 '13 at 16:09
  • Of course. It's for example impossible to implement the "nice looking" lambdas (as we have it now) in C++03. Boost had to use some "expression template trick" with placeholders to implement them. So they are very different. But some other features are very similar in Boost vs. C++11, at least from the usage point of view. A lot of things require language support (and aren't pure library features), so it's impossible to implement them in Boost based on C++03, like variadic templates, r-value refs / move semantics, etc. – leemes Mar 02 '13 at 16:25