是否有一种更优雅的方式来使用具有独立if()s

时间:2018-05-13 19:53:34

标签: c++ if-statement sfml

我目前正在使用SFML for c ++并尝试调整窗口大小但是我发现问题的解决方案并不是很正确,而且我在寻找是否有更好的方法。

我有一个可以多次调整大小的对象,因此它可能适合窗口内部,如果它更大,我必须扩展窗口,如果它更小,我必须缩小窗口。但是我有一个窗口的最小大小,如果对象适合我要将窗口重置为该大小。

这是我现在正在使用的伪代码:

if (Object.getSize().x > window.getSize().x || Object.getSize().y > window.getSize.y){
    if(Object.getSize().x > windowMinSize.x){
        window.resize(Object.getSize().x, window.getSize().y)
    }
    if(Object.getSize().y > windowMinSize.y){
        window.resize(window.getSize().x, Object.getSize().y)
    }
}
else{
    window.resize(windowMinSize);
}

我已经查看了switch和其他选项,但我还没有找到我正在寻找的内容。

4 个答案:

答案 0 :(得分:2)

这里使用的正确模式是限制调用外部方法的代码路径的数量,以便只有一个使用点:

你的伪代码变成这样:

auto new_win_size = windowMinSize;
if (Object.getSize().x > window.getSize().x || Object.getSize().y > window.getSize.y){
    if(Object.getSize().x > windowMinSize.x){
        new_win_size.x = Object.getSize().x;
        new_win_size.y = window.getSize().y;
    }
    if(Object.getSize().y > windowMinSize.y){
        new_win_size.x = window.getSize().x;
        new_win_size.y = Object.getSize().y;
    }
}

window.resize(new_win_size );

但我怀疑你真正想要的是:

auto new_win_size = windowMinSize;

if(Object.getSize().x > windowMinSize.x){
    new_win_size.x = Object.getSize().x;
}
if(Object.getSize().y > windowMinSize.y){
    new_win_size.y = Object.getSize().y;
}

window.resize(new_win_size );

答案 1 :(得分:1)

我有点困惑,因为最后听起来你只想简单地将窗口调整到对象大小,同时保持特定的最小尺寸。

因此,您只需要简单调用std::max()来确定两个输入值的较大值:

unsigned int width = std::max(min_width, object_width);
unsigned int height = std::max(min_height, object_height);

使用新尺寸时,它基本上会调整窗口大小以匹配您的对象,除非该对象小于您的最小尺寸。

您可以使用相同的模式,使用std::min()作为附加图层添加最大尺寸:

unsigned int width = std::min(max_width, std::max(min_width, object_width));
unsigned int height = std::min(max_height, std::max(min_height, object_height));

编辑:正如bolov正确建议的那样,使用新std::clamp的现代编译器可以进一步简化:

unsigned int width = std::clamp(object_width, min_width, max_width);
unsigned int height = std::clamp(object_height, min_height, max_height);

答案 2 :(得分:1)

您可以使用可变参数template来获得您想要的效果。我的版本在这里采用else函数(第一个参数),然后是函数对(谓词,块,谓词,块,......)。如果没有任何谓词计算为true,则将执行else函数。这应该适用于C ++ 11或更高版本。

这里可能存在一些错误(我还没有做过多少测试),但你可以踢掉轮胎。如果您将#if 0更改为#if 1,则可以发现else函数无法被调用。

#include <iostream>

template <typename PRED, typename EXEC>
bool multi_branch_detail(PRED pred, EXEC exec) {
    if(pred()) {
        exec();
        return true;
    }
    return false;
}

template <typename PRED, typename EXEC, typename ...REM>
bool multi_branch_detail(PRED pred, EXEC exec, REM ...rem) {
    auto result = false;
    if(pred()) {
        exec();
        result = true;
    }
    return multi_branch_detail(std::forward<REM>(rem)...) || result;
}

template <typename ELSE, typename ...FNS>
void multi_branch(ELSE el, FNS ...fns) {
    if(!multi_branch_detail(std::forward<FNS>(fns)...)) {
        el();
    }
}


int main() {
    multi_branch(
        []() { std::cout << "No cases\n"; },

#if 0
        []() { return 1 < 2; }, []() { std::cout << "first case\n"; },
        []() { return 10 < 20; }, []() { std::cout << "second case\n"; },
#endif
        []() { return 1 > 2; }, []() { std::cout << "bug\n"; }
    );
    return 0;
}

使用#if 0输出:

No cases

使用#if 1输出:

first case
second case

答案 3 :(得分:1)

我将您的问题解释为询问如何重构以下代码:

if ( A )
{
     if ( B ) { X } else { Y }
     if ( C ) { Z } else { Y }
}
else { Y }

避免重复Y

一种方法是:

bool A = ....;
bool B = ....;
bool C = ....;

if      ( A && B ) { X }
else if ( A && C ) { Z }
else { Y }

虽然与原始代码的短路行为相比,这可能涉及不必要的函数调用。

最“明显”的解决方案是存储变量:

bool updated = false;
if ( A ) 
{
    if ( B ) { X; updated = true; }
    if ( C ) { Z; updated = true; }
}
if ( !updated ) { Y }

另一种方法是使用一个可以突破的控制结构:

do
{
     if ( A )
     {
          if ( B ) { X; break; }
          if ( C ) { Z; break; }
     }
     Y;
} while (0);

有些人不喜欢这个,因为如果你正在阅读代码,看起来我们正在进入一个循环,但后来证明它不是一个循环。就个人而言,我会创建一个函数(break替换为return);但如果使用do...while(0),你应该在开头添加一个代码注释,指出这不是一个循环。