是否可以保存带有参数的函数指针供以后使用?
Is it possible to save a function pointer with arguments for later use?
昨天,我试图编写一个基本的渲染器,其中渲染器控制何时将数据加载到着色器中,而可渲染对象对正在使用的着色器一无所知。作为一个顽固的人(并且没有 运行 睡眠充足),我花了几个小时试图将函数指针发送到渲染器,保存,然后 运行 在适当的时间。直到后来我才意识到我要构建的是一个消息系统。不过,这让我想知道,是否可以在以后的 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
}
我意识到 boost 可能支持某种类似的功能,但我想避免使用 boost。
这样的事情是否可能,一般设计会是什么样子,它甚至会被用来做什么,因为消息总线是这样的事情的更成熟的设计模式?
std::bind
是一种方法,但如果您可以访问 C++ 11 及更高版本,则可能需要考虑改用 lambda。 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;
}
如果要捕获对 x
的引用,请使用 [&x]
。在上面的示例中,结果将是 17(即 15 + 2)。如果您确实使用引用,请注意不要让 x
在 storedFunction
之前超出范围,因为它会成为对垃圾数据的悬空引用。
现在大多数编译器都支持 C++ 11,但您可能需要在项目设置中明确添加支持:
- Visual Studio:项目Properties/C++/Language/C++语言标准
- gcc:
--std=c++11
(或 14,或 17...)
- CMake 还允许您设置标准:
set (CMAKE_CXX_STANDARD 11)
Is it possible to save function pointers with arguments directly to be
run at a later time in c++.
是,就是。
首先,如果您已经在使用 C++11 或更高版本,则不需要 boost 来处理您当前的问题。
最简单直观的方法是,将所有函数作为 lambda 函数(即 return lambda)并存储到您的
std::queue<storableFunction> instruction;
您将在此处找到有关 lambda 的详细说明:What is a lambda expression in C++11?
提供 storableFunction
的想法很好,因为您可以明确地为每个要存储到 modelObj
的成员函数指明函数指针类型。
但是,如果考虑存储到某些 STL 容器,则需要使用 std::function
, with some type erasure overhead, which can deal with the different lambda functions,能够捕获范围内的变量)。
这里是 an example code 和 std::vector
#include <iostream>
#include <vector>
#include <functional>
int main()
{
int arg1 = 4;
std::string arg2 = "String";
std::vector<std::function<void()>> vecFunPtr
{
[](int arg1 = 1){ std::cout << arg1 << std::endl; },
[](float arg1 = 2.0f){ std::cout << arg1 << std::endl; },
[](double arg1 = 3.0){ std::cout << arg1 << std::endl; },
[&arg1, &arg2](){ std::cout << arg1 << " " << arg2 << std::endl; }
};
for(const auto& funs: vecFunPtr) funs(); // call the stored lambdas
return 0;
}
输出:
1
2
3
4 String
在你的情况下,Renderer
可以这样写。需要注意的一件事是,您需要采取一些变通方法来将不同的参数传递给成员函数(或者肯定是 lambda 捕获。)
旁注:Here您会找到一些技巧来避免因std::function
而导致的性能问题,这可能会有所帮助。
class Renderer
{
typedef std::queue<std::function<void()>> modelObj; // you might need modelObj for only this class
typedef std::function<void()> fFunPtr; // typedef for void(*)() using std::function
std::map<int, modelObj> models;
public:
// renderer functions can be written like returning a lambda
fFunPtr rFun1(int arg1) { return [](int arg1 = 1){ std::cout << arg1 << std::endl; }; }
fFunPtr rFun2(double arg1) { return [](float arg1 = 2.0f){ std::cout << arg1 << std::endl; }; }
// function to store them for latter use
void pushInputDataInstruction(const int id, const fFunPtr& funPtr)
{
models[id].push(funPtr);
}
};
int main()
{
Renderer objRender;
//do stuff
while(/*condition*/)
{
//do stuff
objRender.pushInstruction(/* id number, function pointer*/)
renderer.render();
}
return 0;
}
昨天,我试图编写一个基本的渲染器,其中渲染器控制何时将数据加载到着色器中,而可渲染对象对正在使用的着色器一无所知。作为一个顽固的人(并且没有 运行 睡眠充足),我花了几个小时试图将函数指针发送到渲染器,保存,然后 运行 在适当的时间。直到后来我才意识到我要构建的是一个消息系统。不过,这让我想知道,是否可以在以后的 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
}
我意识到 boost 可能支持某种类似的功能,但我想避免使用 boost。
这样的事情是否可能,一般设计会是什么样子,它甚至会被用来做什么,因为消息总线是这样的事情的更成熟的设计模式?
std::bind
是一种方法,但如果您可以访问 C++ 11 及更高版本,则可能需要考虑改用 lambda。 Scott Meyer 建议在 Effective Modern C++.
一个 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;
}
如果要捕获对 x
的引用,请使用 [&x]
。在上面的示例中,结果将是 17(即 15 + 2)。如果您确实使用引用,请注意不要让 x
在 storedFunction
之前超出范围,因为它会成为对垃圾数据的悬空引用。
现在大多数编译器都支持 C++ 11,但您可能需要在项目设置中明确添加支持:
- Visual Studio:项目Properties/C++/Language/C++语言标准
- gcc:
--std=c++11
(或 14,或 17...) - CMake 还允许您设置标准:
set (CMAKE_CXX_STANDARD 11)
Is it possible to save function pointers with arguments directly to be run at a later time in c++.
是,就是。
首先,如果您已经在使用 C++11 或更高版本,则不需要 boost 来处理您当前的问题。
最简单直观的方法是,将所有函数作为 lambda 函数(即 return lambda)并存储到您的
std::queue<storableFunction> instruction;
您将在此处找到有关 lambda 的详细说明:What is a lambda expression in C++11?
提供 storableFunction
的想法很好,因为您可以明确地为每个要存储到 modelObj
的成员函数指明函数指针类型。
但是,如果考虑存储到某些 STL 容器,则需要使用 std::function
, with some type erasure overhead, which can deal with the different lambda functions,能够捕获范围内的变量)。
这里是 an example code 和 std::vector
#include <iostream>
#include <vector>
#include <functional>
int main()
{
int arg1 = 4;
std::string arg2 = "String";
std::vector<std::function<void()>> vecFunPtr
{
[](int arg1 = 1){ std::cout << arg1 << std::endl; },
[](float arg1 = 2.0f){ std::cout << arg1 << std::endl; },
[](double arg1 = 3.0){ std::cout << arg1 << std::endl; },
[&arg1, &arg2](){ std::cout << arg1 << " " << arg2 << std::endl; }
};
for(const auto& funs: vecFunPtr) funs(); // call the stored lambdas
return 0;
}
输出:
1
2
3
4 String
在你的情况下,Renderer
可以这样写。需要注意的一件事是,您需要采取一些变通方法来将不同的参数传递给成员函数(或者肯定是 lambda 捕获。)
旁注:Here您会找到一些技巧来避免因std::function
而导致的性能问题,这可能会有所帮助。
class Renderer
{
typedef std::queue<std::function<void()>> modelObj; // you might need modelObj for only this class
typedef std::function<void()> fFunPtr; // typedef for void(*)() using std::function
std::map<int, modelObj> models;
public:
// renderer functions can be written like returning a lambda
fFunPtr rFun1(int arg1) { return [](int arg1 = 1){ std::cout << arg1 << std::endl; }; }
fFunPtr rFun2(double arg1) { return [](float arg1 = 2.0f){ std::cout << arg1 << std::endl; }; }
// function to store them for latter use
void pushInputDataInstruction(const int id, const fFunPtr& funPtr)
{
models[id].push(funPtr);
}
};
int main()
{
Renderer objRender;
//do stuff
while(/*condition*/)
{
//do stuff
objRender.pushInstruction(/* id number, function pointer*/)
renderer.render();
}
return 0;
}