如何在 C++11 中模拟没有 lambda 表达式的嵌套函数?
How can I simulate a nested function without lambda expressions in C++11?
我有以下代码:
int main(int argc, char **argv)
{
App app(800, 600);
app.add_event_scene(Scene("Event Plot", event_plot));
Image x("sample.png");
struct foo { static void visual_plot() { x.draw(); } }; // Error.
app.add_visual_scene(Scene("Visual Plot", foo::visual_plot));
app.run();
return 0;
}
我收到以下错误:
||=== Build: Debug in Joy-Plus-Plus (compiler: GNU GCC Compiler) ===|
G:\Development\Game-Development\CB\Joy-Plus-Plus\main.cpp|54|error: use of local variable with automatic storage from containing function|
G:\Development\Game-Development\CB\Joy-Plus-Plus\main.cpp|53|error: 'Image x' declared here|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
I'm writing a multimedia/game engine for the Allegro 5 library,我已经将主循环的绘图部分(以及事件部分)抽象为 "scene" 带有绘图(函数)的对象。每个过程都传递给应用程序,以便它在主循环中得到 "run"。问题是,"C++ approach" 不起作用:
Image x("sample.png");
void visual_plot()
{
x.draw(); // Problem.
}
int main(int argc, char **argv)
{
App app(800, 600);
app.add_event_scene(Scene("Event Plot", event_plot));
app.add_visual_scene(Scene("Visual Plot", visual_plot));
app.run();
return 0;
}
虽然代码运行了,但是出现了这样的情况:
如果我将 x 放在 visual_plot 中,图像将正常加载:
但现在我遇到了一个巨大的性能问题,因为在每个主循环中都会创建一个新的 Image 对象(并且很快整个事情就会冻结)。
当我把它放在函数范围之外时找不到图像,因为它必须在应用程序初始化之后,但是因为我有一个typedef函数指针将该函数作为参数的场景,我也必须给它一个void函数。问题是我无法在 C++ 中创建本地/嵌套函数(在应用程序初始化之后)。所以,为了避免这个问题,我尝试了明显的(Lambda表达式/闭包):
int main(int argc, char **argv)
{
App app(800, 600);
app.add_event_scene(Scene("Event Plot", event_plot));
Image x("sample.png");
app.add_visual_scene(Scene("Visual Plot", [&x]()->void{x.draw();}));
app.run();
return 0;
}
问题是Scene的构造函数的第二个参数接受了一个函数指针:
typedef void(*plot)();
typedef map<string, plot> act;
class Scene
{
private:
string name;
plot p;
public:
Scene(string name, plot p);
~Scene() {};
string get_name();
plot get_plot();
void set_name(string value);
void set_plot(plot value);
};
并且由于函数不能作为参数传递,并且会衰减为指针,这同样适用于 lambda 表达式(它不是函数),所以我得到以下错误:
G:\Development\Game-Development\CB\Joy-Plus-Plus\main.cpp|52|error: no matching function for call to 'Scene::Scene(const char [12], main(int, char**)::__lambda0)'|
面对这样的悲剧,我该如何在C++11中模拟一个嵌套函数呢? Since simulating like this answer 不起作用。
OBS:我同意这可能是设计问题,但我几乎不这么认为。对我来说,C++ 就是不想让我以任何方式将那个该死的函数作为参数传递(所以,我请求各位 C++ 高手的帮助)。
只需将图像放入 visual_plot
函数并使其静态化即可:
void visual_plot()
{
static Image img("sample.png");
x.draw(); // Problem.
}
这将在第一次调用 visual_plot
时初始化 img
,并且仅在那时。这将同时解决性能问题和 "it must be initialized after app.run()
" 问题。
这是一个设计问题。为了完成您正在尝试做的事情,您需要两条信息:要执行的代码和要执行的数据。
lambda 并不神奇,它只是将这两者封装到一个对象中,这就是为什么它不能很好地退化为单个函数指针。带捕获的 lambda 是函数对象的语法糖:
int x, y;
float f;
// ...
auto l = [x, &y, f] () { return static_cast<int>((x + y) * f); };
int r = l();
让您免于写作
struct Values {
int x;
int& y;
float f;
int operator() () {
return static_cast<int>((x + y) * f);
}
Capture(int x_, int& y_, float f_) : x(x_), y(y_), f(f_) {}
};
//...
Capture c(x, y, f);
int r = c();
最后是一个成员函数调用,所以涉及两个指针:一个指向成员函数的指针 'operator()' 和一个指向调用它的实例的指针。
int r = Capture::operator=(&c); // pseudo
使用静态或全局变量,您可以在编译时知道数据的地址,这样您就只需要一个函数指针。
但是您的设计是只接受一个参数的 strcpy 或接受一个参数的打印函数 none:您怎么知道要复制或打印什么?
更好的设计要么让您将函数对象传递给绘图函数,看看 STL 谓词如何工作,这将允许函数指针和 lambda,要么使用虚函数和子类化。
struct Scene { virtual void plot(); };
struct MyScene : public Scene {
Image x;
MyScene() : x("image") {}
void plot() override { x.draw(); }
};
这种方法的缺陷是“slicing”,如果允许派生类型,则需要通过引用而不是值传递 Scene
:
void foo(Scene& s) {
s.plot();
}
foo(MyScene(...)); // not going to go well
我有以下代码:
int main(int argc, char **argv)
{
App app(800, 600);
app.add_event_scene(Scene("Event Plot", event_plot));
Image x("sample.png");
struct foo { static void visual_plot() { x.draw(); } }; // Error.
app.add_visual_scene(Scene("Visual Plot", foo::visual_plot));
app.run();
return 0;
}
我收到以下错误:
||=== Build: Debug in Joy-Plus-Plus (compiler: GNU GCC Compiler) ===|
G:\Development\Game-Development\CB\Joy-Plus-Plus\main.cpp|54|error: use of local variable with automatic storage from containing function|
G:\Development\Game-Development\CB\Joy-Plus-Plus\main.cpp|53|error: 'Image x' declared here|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
I'm writing a multimedia/game engine for the Allegro 5 library,我已经将主循环的绘图部分(以及事件部分)抽象为 "scene" 带有绘图(函数)的对象。每个过程都传递给应用程序,以便它在主循环中得到 "run"。问题是,"C++ approach" 不起作用:
Image x("sample.png");
void visual_plot()
{
x.draw(); // Problem.
}
int main(int argc, char **argv)
{
App app(800, 600);
app.add_event_scene(Scene("Event Plot", event_plot));
app.add_visual_scene(Scene("Visual Plot", visual_plot));
app.run();
return 0;
}
虽然代码运行了,但是出现了这样的情况:
如果我将 x 放在 visual_plot 中,图像将正常加载:
但现在我遇到了一个巨大的性能问题,因为在每个主循环中都会创建一个新的 Image 对象(并且很快整个事情就会冻结)。
当我把它放在函数范围之外时找不到图像,因为它必须在应用程序初始化之后,但是因为我有一个typedef函数指针将该函数作为参数的场景,我也必须给它一个void函数。问题是我无法在 C++ 中创建本地/嵌套函数(在应用程序初始化之后)。所以,为了避免这个问题,我尝试了明显的(Lambda表达式/闭包):
int main(int argc, char **argv)
{
App app(800, 600);
app.add_event_scene(Scene("Event Plot", event_plot));
Image x("sample.png");
app.add_visual_scene(Scene("Visual Plot", [&x]()->void{x.draw();}));
app.run();
return 0;
}
问题是Scene的构造函数的第二个参数接受了一个函数指针:
typedef void(*plot)();
typedef map<string, plot> act;
class Scene
{
private:
string name;
plot p;
public:
Scene(string name, plot p);
~Scene() {};
string get_name();
plot get_plot();
void set_name(string value);
void set_plot(plot value);
};
并且由于函数不能作为参数传递,并且会衰减为指针,这同样适用于 lambda 表达式(它不是函数),所以我得到以下错误:
G:\Development\Game-Development\CB\Joy-Plus-Plus\main.cpp|52|error: no matching function for call to 'Scene::Scene(const char [12], main(int, char**)::__lambda0)'|
面对这样的悲剧,我该如何在C++11中模拟一个嵌套函数呢? Since simulating like this answer 不起作用。
OBS:我同意这可能是设计问题,但我几乎不这么认为。对我来说,C++ 就是不想让我以任何方式将那个该死的函数作为参数传递(所以,我请求各位 C++ 高手的帮助)。
只需将图像放入 visual_plot
函数并使其静态化即可:
void visual_plot()
{
static Image img("sample.png");
x.draw(); // Problem.
}
这将在第一次调用 visual_plot
时初始化 img
,并且仅在那时。这将同时解决性能问题和 "it must be initialized after app.run()
" 问题。
这是一个设计问题。为了完成您正在尝试做的事情,您需要两条信息:要执行的代码和要执行的数据。
lambda 并不神奇,它只是将这两者封装到一个对象中,这就是为什么它不能很好地退化为单个函数指针。带捕获的 lambda 是函数对象的语法糖:
int x, y;
float f;
// ...
auto l = [x, &y, f] () { return static_cast<int>((x + y) * f); };
int r = l();
让您免于写作
struct Values {
int x;
int& y;
float f;
int operator() () {
return static_cast<int>((x + y) * f);
}
Capture(int x_, int& y_, float f_) : x(x_), y(y_), f(f_) {}
};
//...
Capture c(x, y, f);
int r = c();
最后是一个成员函数调用,所以涉及两个指针:一个指向成员函数的指针 'operator()' 和一个指向调用它的实例的指针。
int r = Capture::operator=(&c); // pseudo
使用静态或全局变量,您可以在编译时知道数据的地址,这样您就只需要一个函数指针。
但是您的设计是只接受一个参数的 strcpy 或接受一个参数的打印函数 none:您怎么知道要复制或打印什么?
更好的设计要么让您将函数对象传递给绘图函数,看看 STL 谓词如何工作,这将允许函数指针和 lambda,要么使用虚函数和子类化。
struct Scene { virtual void plot(); };
struct MyScene : public Scene {
Image x;
MyScene() : x("image") {}
void plot() override { x.draw(); }
};
这种方法的缺陷是“slicing”,如果允许派生类型,则需要通过引用而不是值传递 Scene
:
void foo(Scene& s) {
s.plot();
}
foo(MyScene(...)); // not going to go well