是否可以使用参数保存函数指针以供以后使用?

Jus*_*n W 3 c++ function-pointers class function

昨天,我试图编写一个基本渲染器,渲染器在数据加载到着色器时控制渲染器,而渲染对象不知道所使用的着色器.作为一个顽固的人(而不是睡眠不足),我花了几个小时试图将函数指针发送到渲染器,保存,然后在适当的时间运行.直到后来我意识到我想要构建的是一个消息系统.它让我想知道,是否可以直接保存带参数的函数指针,以便稍后在c ++中运行.

我最初的想法看起来像这样:

//set up libraries and variables
Renderer renderer();
renderable obj();
mat4 viewMatrix();
// renderer returns and object id
int objID = renderer.loadObj(obj)

int main()
{
  //do stuff
  while(running)
  {
    //do stuff
    renderer.pushInstruction(//some instruction);
    renderer.render();
  }
}

// functionPtr.h
#include <functional>

class storableFunction
{
  public:
  virtual ~storableFunction = 0;
  virtual void call() = 0;
};

template<class type>
class functionPtr : public storableFunction
{
  std::function<type> func;
public:
  functionPtr(std::function<type> func)
    : func(func) {}
  void call() { func(); }
};

//renderer.h
struct  modelObj
{
  // model data and attached shader obj
  std::queue<storableFunction> instruction;
}

class renderer
{
  std::map<int, modelObj> models;
public:
    // renderer functions
    void pushInputDataInstruction(int id, //function, arg1, arg2);
    // this was overloaded because I did not know what type the second argument  would be
    // pushInputDataInstruction implementation in .cpp
    {
      models[id].instruction.push(functionPtr(std::bind(//method with args)))
    }
  void render();
};

//implantation in .cpp
{
  for(// all models)
  //bind all data
  applyInstructions(id);
  // this would call all the instructrions using functionptr.call() in the queue and clear the queue
  draw();
  // unbind all data
}
Run Code Online (Sandbox Code Playgroud)

我意识到boost可能支持某种类似的功能,但我想避免使用boost.

这样的事情是可能的,一般的设计会是什么样的,甚至用什么来看待消息总线是一个更加成熟的设计模式呢?

Bar*_*der 6

std::bind是一种方法,但如果您可以访问C++ 11及更高版本,则可能需要考虑使用lambdas.Scott Meyer建议他们在Effective Modern C++中使用std :: bind(在大多数情况下).

lambda有三个部分:

  • []一部分,其标识值或引用来捕捉,
  • ()部分,用于标识稍后将在调用lambda时提供的参数.
  • {}部分,用于标识如何处理捕获的值和参数

简单的例子:

#include <iostream>

void printValue(int x) {
    std::cout << x << std::endl;
}

int main(int argc, char * argv[]) {
    int x = 23;

    // [x] means 'capture x's value, keep it for later'
    // (int y) means 'I'll provide y when I invoke the lambda'
    auto storedFunction = [x](int y){return printValue(x + y);};

    x = 15;

    // Now we invoke the lamda, with y = 2
    // Result: 25 (23 + 2), even if x was changed after the lambda was created
    storedFunction(2); 
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果要捕获引用x,请使用[&x].在上面的例子中,结果将是17(即15 + 2).如果您确实使用了引用,请注意不要让它x超出范围之前storedFunction,因为它将成为垃圾数据的悬空引用.

大多数编译器现在支持C++ 11,但您可能需要在项目设置中明确添加支持:

  • Visual Studio:项目属性/ C++ /语言/ C++语言标准
  • gcc :( --std=c++11或14或17 ......)
  • CMake还允许您设置标准: set (CMAKE_CXX_STANDARD 11)

  • 澄清一下:`std :: bind`也需要C++ 11. (2认同)