Search code examples
c++c++11stdbind

rebind one parameter of std::function


In my C++ project I decided to give the new++ features a try. One of those features is the binding of a function with std::function via std::bind.

Now I came to a use case, where I have to rebind the std::function.

Consider the following simplified code:

class Test
{
public:
    void first()
    {
        second(bind(&Test::third, this));
    }

    void second(function<void()> fun)
    {
        Test *other = new Test();
        fun->rebindLastParameter(other); // How can I do this?
        fun();
    }

    void third()
    {
        // This is called in context of "other"
    }
}

How can I do the fun->rebindLastParameter(other); part (replace this pointer with other)?

(EDIT) Context:

In my application there are several classes which inherit from a class called BaseModel. Those classes are automatically transpiled from a self made description language. The following class represents a simple "asteroid" which consists of two other "asteroids":

#pragma once

#include "BaseModel.h"
#include <functional>

using namespace std;
using namespace std::placeholders;

class Test : public BaseModel
{
public:
  Test(const OBB& start_obb) : BaseModel(start_obb) {}

  void __init() {
    scene();
  }
  void scene() {
      combine(bind(&Test::asteroid, this),bind(&Test::asteroid, this));
  }

  void asteroid() {
      translate(random_float(),random_float(),random_float());
      sphere(7);
      repeat(400,bind(&Test::impact, this));
  }

  void impact() {
      auto p1 = random_surface_point();
      select_sphere(p1,random_float() * 2 + 1,1.0);
      normalize(p1);
      translate_selection(-p1 * random_float() * 0.4);
  }

};

The problem lies in the function BaseModel::combine, that combines (via constructive solid geometry) two new objects (1st asteroid and 2nd asteroid):

void BaseModel::combine(function<void()> left, function<void()> right)
{
    BaseModel *leftModel = (BaseModel*) ::operator new (sizeof(BaseModel));
    BaseModel *rightModel = (BaseModel*) ::operator new (sizeof(BaseModel));
    leftModel->initWithStartOBB(*this->obb);
    rightModel->initWithStartOBB(*this->obb);

    auto newLeft = bind(left, leftModel); // This does not work
    auto newRight = bind(right, rightModel);  // This does not work

    newLeft();
    newRight();

   // ... CSG stuff
}

As leftModel and rightModel have to be new models of the same class, I need to rebind the first parameter I previously give in my automatically transpiled class Test::scene.

Perhaps I'm on the wrong track. I hope that additional context could explain why I've run into that problem.


Solution

  • std::mem_fn is what you are looking for, as it generates wrapper objects for pointers to members.

    std::function<void(Test*)> f = std::mem_fn(&Test::third);
    f(this);
    Test *other = new Test();
    f(other);
    

    With std::bind, use fun with a reference to Test object. This way you can call it with a new object

    void second(std::function<void(const Test&)> fun)
    {
        Test *other = new Test();
        fun(*other);
    }
    

    Or with this object

    fun(*this);