Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/actionscript-3/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
一种轮询事件API的设计 你说你正在设计一个C++窗口库。它可能提供回调API,也可能不提供回调API,但需要提供轮询API以促进功能性编程风格_C++_Api_Events_Polling - Fatal编程技术网

一种轮询事件API的设计 你说你正在设计一个C++窗口库。它可能提供回调API,也可能不提供回调API,但需要提供轮询API以促进功能性编程风格

一种轮询事件API的设计 你说你正在设计一个C++窗口库。它可能提供回调API,也可能不提供回调API,但需要提供轮询API以促进功能性编程风格,c++,api,events,polling,C++,Api,Events,Polling,轮询API是什么样子的 一些选择 SDL风格 struct事件{ 枚举{MousePress,KeyPress}类型; 联合{ 结构{点位置;鼠标按钮b;}鼠标按下; 结构{修饰符mods;字符键;}按键; }; }; void userCode(){ 对于(;;){ 事件e;如果(事件(&e)){ 开关(e型){ case MousePress:cout为了快速回答您的问题,我更喜欢“SDL风格代码”的简单性。主要是因为稍微复杂一点的“状态风格”浪费内存,完全买不到任何东西(见下文),而您饱受

轮询API是什么样子的

一些选择 SDL风格
struct事件{
枚举{MousePress,KeyPress}类型;
联合{
结构{点位置;鼠标按钮b;}鼠标按下;
结构{修饰符mods;字符键;}按键;
};
};
void userCode(){
对于(;;){
事件e;如果(事件(&e)){
开关(e型){

case MousePress:cout为了快速回答您的问题,我更喜欢“SDL风格代码”的简单性。主要是因为稍微复杂一点的“状态风格”浪费内存,完全买不到任何东西(见下文),而您饱受折磨的“函数伪C++风格”中的递归将在几毫秒内溢出堆栈

“State Style”:您在“State Style”代码中的“typesafe yay”有点不合理。您仍然在根据另一个成员上的
开关来决定访问哪个成员,因此该代码与“SDL Style”具有相同的弱点代码有——对于SDL样式代码可能导致将内存解释为错误类型的任何错误,您都会犯同样严重的错误,即使用状态样式代码访问未初始化的成员

“Functional pseudo-C++style”:现在您已经取得了一些进展,从基本事件类型继承了不同的事件类型。显然,愚蠢的递归需要变成一个循环,还有一些小事情需要整理(我认为您的3个名为
transform()的方法)
UserWidget
中的
handle()
;我猜您可以使用Boost.Function或类似工具解决无模板虚拟方法的问题。我认为这种方法有潜力,尽管我更喜欢SDL样式的简单性


但更根本的是:我质疑是否需要一个轮询接口。
pollEvent()
无法阻止有什么原因吗?目前,所有3个代码段都在99.99%的时间里无所事事地消耗CPU时间。

为了快速回答您的问题,我更喜欢简单的“SDL风格代码”。这主要是因为稍微复杂一点的“状态样式”浪费了内存,完全买不到任何东西(请参见下文),而您饱受折磨的“函数伪C++”样式中的递归将在几毫秒内溢出堆栈

“State Style”:您在“State Style”代码中的“typesafe yay”有点不合理。您仍然在根据另一个成员上的
开关来决定访问哪个成员,因此该代码与“SDL Style”具有相同的弱点代码有——对于SDL样式代码可能导致将内存解释为错误类型的任何错误,您都会犯同样严重的错误,即使用状态样式代码访问未初始化的成员

“Functional pseudo-C++style”:现在您已经取得了一些进展,从基本事件类型继承了不同的事件类型。显然,愚蠢的递归需要变成一个循环,还有一些小事情需要整理(我认为您的3个名为
transform()的方法)
UserWidget
中的
handle()
;我猜您可以使用Boost.Function或类似工具解决无模板虚拟方法的问题。我认为这种方法有潜力,尽管我更喜欢SDL样式的简单性


但更根本的是:我质疑是否需要一个轮询接口
无法阻止?目前,所有3个代码段99.99%的时间都在浪费CPU时间。StateStyle是类型安全的。pollInput返回完整的对象。例如,即使对于鼠标单击,返回的事件也有正确的键盘数组。是的,我对递归很傻。现在,我在和Haskell鬼混-它优化了尾部递归到一个循环中,这样就不会出现堆栈溢出:)我非常喜欢FP的想法,即通过“转换”最小化可变状态。使用您建议的通知系统(“句柄”)确实解决了模板问题,因为我不再需要模板,但迫使我进入命令式编程。哦,我猜我不能做Haskell在C++中),如果我放开它,那么就不需要轮询接口,不。IAC是用于游戏类应用程序,我在这里烧了100%个CPU。关于类型安全:我的观点是类型安全。正确性不是最终目标,虽然您的“状态样式”方法在技术上是类型安全的,但它与本例中的非类型安全SDL样式具有完全相同的弱点。我对UserWidget中的s/transform/handle/g的建议只是因为transform()调用方法“handle()”,而不是方法“transform()”。(因此,您的原始代码无法编译。)它没有消除对模板的需要——正如你所说,你需要一个基类。StateStyle是类型安全的。pollInput返回完整的对象。例如,即使对于鼠标点击,返回的事件也有一个正确的键盘数组。是的,我对递归很傻。现在和Haskell鬼混——它优化了尾部递归into一个循环,这样就不会有堆栈溢出:)我非常喜欢FP的想法,即最小化可变状态,因此使用“转换”。使用您建议的通知系统(“句柄”)确实解决了模板问题,因为我不再需要模板,但迫使我进入命令式编程。哦,我猜我不能做Haskell在C++中),如果我放开它,那么就不需要轮询接口,不。IAC是用于游戏类应用程序,我在这里烧了100%个CPU。关于类型安全:我的观点是类型安全。正确性不是最终目标,虽然您的“状态样式”方法在技术上是类型安全的,但在本例中它与非类型安全的SDL样式具有完全相同的弱点
struct Event {
    enum { MousePress, KeyPress } type;
    union {
        struct { Point pos; MouseButton b; } mousePress;
        struct { Modifiers mods; char key; } keyPress;
    };
};
void userCode() {
    for(;;) {
        Event e; if(pollEvent(&e)) {
            switch(e.type) {
                case MousePress: cout<<event.mousePress.pos.x; break; // not typesafe
                case KeyPress: cout<<event.keyPress.key; break;
            }
        }
    }
}
struct Input {
    enum { Mouse, Keyboard, Nothing } whatChanged;
    MouseButtonsBitfield pressedButtons;
    bool keysPressed[keyCount];
};
void userCode() {
    for(;;) {
        Input in = pollInput();
        switch(in.whatChanged) {
            // typesafe yay
            case Mouse: cout << "is LMB pressed? " << bool(in.pressedButtons&LeftButton); break;
            case Keyboard: cout << "is A pressed? " << in.keysPressed['A']; break;
        }
    }
}
struct Event {
    // transforms listener by notifying it of event,
    // returns transormed listener. nondestructive.
    template<class Listener> // sadly invalid, templates can't be virtual.
                                              // a solution is to make Listener the base
                                              // of a hierarchy and make Listener::handle virtual
                                              // but then we're forced to use imperative style
    virtual Listener transform(Listener const&) =0;
};
struct MousePress : Event { // yay we're extensible via inheritance
    template<class Listener>
    virtual Listener transform(Listener const& listener) {
        return listener.handle(*this); // calls the MousePress overload
    }
    Point pos; MouseButton b;
};
struct KeyPress : Event {
    template<class Listener>
    virtual Listener transform(Listener const& listener) {
        return listener.handle(*this); // calls the KeyPress overload
    }
    Modifiers mods; char key;
};
struct NoEvent : Event {
    template<class Listener>
    virtual Listener transform(Listener const& listener) {
        return listener.handle(*this);
    }
};
struct UserWidget {
    UserWidget handle(NoEvent) {
        return UserWidget();
    }
    UserWidget handle(MousePress p) {
        return (UserWidget) { string("pressed at")+lex_cast<string>(p.pos)) };
    }
    UserWidget handle(KeyPress k) {
        return (UserWidget) { string("pressed key=")+lex_cast<string>(k.key)) };
    }
    string pendingOutput;
};
void userTick(UserWidget const& w) {
    cout<<w.pendingOutput;
    userTick(pollEvent().transform(w));
}
void userCode() {
    userTick(UserWidget());
}