Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.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
C++ 如何在多个条件下进行分支/切换?_C++_C++11 - Fatal编程技术网

C++ 如何在多个条件下进行分支/切换?

C++ 如何在多个条件下进行分支/切换?,c++,c++11,C++,C++11,有没有一种方法可以在多个条件下进行分支,而不编写看起来一团糟的代码?最好使用C++11或C++14中的合成糖 #include <iostream> enum state { STATE_1, STATE_2, STATE_3, STATE_4, STATE_5, STATE_6, STATE_7, STATE_8, }; state f(int a, bool b, const std::string& s

有没有一种方法可以在多个条件下进行分支,而不编写看起来一团糟的代码?最好使用C++11或C++14中的合成糖

#include <iostream>

enum state
{
    STATE_1,
    STATE_2,
    STATE_3,
    STATE_4,
    STATE_5,
    STATE_6,
    STATE_7,
    STATE_8,
};

state f(int a, bool b, const std::string& str)
{
    // How not to:
    if (a < 0)
    {
        if (b == false)
        {
            if (str != "morning")
            {
                return STATE_1;
            }
            else
            {
                return STATE_2;
            }
        }
        else
        {
            if (str != "morning")
            {
                return STATE_3;
            }
            else
            {
                return STATE_4;
            }
        }
    }
    else // a >= 0
    {
        if (b == false)
        {
            if (str != "morning")
            {
                return STATE_5;
            }
            else
            {
                return STATE_6;
            }
        }
        else
        {
            if (str != "morning")
            {
                return STATE_7;
            }
            else
            {
                return STATE_8;
            }
        }
    }
}

int main()
{
    std::cout << "State: " << f(1, true, "morning") << std::endl;
}
#包括
枚举状态
{
州1,
州2,
州3,
州4,
州5,
州6,
第7州,
州8,
};
状态f(int a、bool b、const std::string和str)
{
//如何避免:
if(a<0)
{
如果(b==false)
{
如果(str!=“早上”)
{
返回状态_1;
}
其他的
{
返回状态_2;
}
}
其他的
{
如果(str!=“早上”)
{
返回状态_3;
}
其他的
{
返回状态_4;
}
}
}
else//a>=0
{
如果(b==false)
{
如果(str!=“早上”)
{
返回状态_5;
}
其他的
{
返回状态_6;
}
}
其他的
{
如果(str!=“早上”)
{
返回状态_7;
}
其他的
{
返回状态_8;
}
}
}
}
int main()
{

std::cout可以在编译时将布尔值(条件结果)列表嵌入POD中,并在POD上切换

用法:
main.cpp
使用编译
g++-std=c++14-O2-Wall-pedantic main.cpp

工作原理
mswitch
mcase
对象只需构建(如果可能,在编译时使用
constepr
函数)BooLISH列表与 <代码> >代码>长Lo/<代码>之间。由于Mase< /Cult> s给出了编译时常数,所有的<>代码>开关>代码>标签实际上是相邻的编译时间常数。

< P>作为C++的基本功能的替代答案,也可以考虑使用三元运算符。

enum state
{
    STATE_1,
    STATE_2,
    STATE_3,
    STATE_4,
    STATE_5,
    STATE_6,
    STATE_7,
    STATE_8,
};

state f(int a, bool b, const std::string& str)
{
    // How not to:
    if (a < 0)
        return b == true ? (str == "morning" ? STATE_4 : STATE_3) : (str == "morning" ? STATE_2 : STATE_1);
    else // a >= 0
        return b == true ? (str == "morning" ? STATE_8 : STATE_7) : (str == "morning" ? STATE_6 : STATE_5);
}

int main()
{
    std::cout << "State: " << f(1, true, "morning") << std::endl;
}
枚举状态
{
州1,
州2,
州3,
州4,
州5,
州6,
第7州,
州8,
};
状态f(int a、bool b、const std::string和str)
{
//如何避免:
if(a<0)
返回b==true?(str==“上午”?状态_4:状态_3):(str==“上午”?状态_2:状态_1);
else//a>=0
返回b==true?(str==“上午”?状态8:状态7):(str==“上午”?状态6:状态5);
}
int main()
{

std::cout我会为以下内容制作一个查找表:

#include <iostream>
#include <string>

enum state {
  STATE_1,
  STATE_2,
  STATE_3,
  STATE_4,
  STATE_5,
  STATE_6,
  STATE_7,
  STATE_8,
};

state f(int a, bool b, const std::string& str) {
  static const state table[2][2][2] = {
    STATE_8, // 0, 0, 0
    STATE_7, // 0, 0, 1
    STATE_6, // 0, 1, 0
    STATE_5, // 0, 1, 1
    STATE_4, // 1, 0, 0
    STATE_3, // 1, 0, 1
    STATE_2, // 1, 1, 0
    STATE_1  // 1, 1, 1
  };
  return table[a < 0][b == false][str != "morning"];
}

int main() {
  std::cout << f(1, true, "morning") << std::endl;
}
#包括
#包括
枚举状态{
州1,
州2,
州3,
州4,
州5,
州6,
第7州,
州8,
};
状态f(int a、bool b、const std::string和str){
静态常量状态表[2][2][2]={
状态8,//0,0,0
状态7,//0,0,1
状态6,//0,1,0
状态5,//0,1,1
状态4,//1,0,0
状态3,//1,0,1
状态2,//1,1,0
州1//1,1,1
};
返回表[a<0][b==false][str!=“morning”];
}
int main(){

STD::CUT< P>我同意,模式匹配在那里非常适合。不幸的是,内置的代码>开关 >在C++中非常有限。

编译时布尔包的实现非常简单

#include <type_traits>

namespace detail
{
    constexpr std::size_t pack_bool(std::size_t result)
    {
        return result;
    }

    template<typename T, typename... Ts>
    constexpr std::size_t pack_bool(std::size_t result, T arg, Ts... args)
    {
        static_assert(std::is_same<bool, T>::value, "boolean expected");
        return pack_bool((result << 1) | arg, args...);
    }
}

template<typename T, typename... Ts>
constexpr std::size_t pack_bool(T arg, Ts... args)
{
    static_assert(std::is_same<bool, T>::value, "boolean expected");
    return detail::pack_bool(arg, args...);
}
以下是我的版本:

特征:
  • 保留编译器对缺失案例的检查,并提供关于哪些案例缺失的信息。

  • 案例的编译时评估意味着零运行时开销

  • 没有宏污染全局命名空间并随机阻止仅标头库工作:-)

  • 缺点:
  • 预定义一些样板枚举的要求(仅一次,在我为您所做的库中)
  • 代码: 运行时输出:
    @Bathsheba在我给出的用例中,
    mswitch::mswitch
    对象是用运行时值构造的。在这种情况下,从布尔列表到
    long
    的转换是在运行时完成的。谢谢。所以这在各个方面都是一个很好的答案。是否指定了
    true
    转换为
    1
    ?我知道s确保
    false
    转换为
    0
    ,但如果我回忆正确,
    true
    转换为
    0
    以外的任何内容。无论如何,这是一个好方法。@YSC它被很好地指定。根据积分提升,类型
    bool
    可以转换为
    int
    ,值
    false
    变成
    ​0
    ​ 和
    true
    变为
    1
    。请参见本页。与模板式答案不同,这实际上看起来更好,并且可以在上下文中立即理解。我喜欢这样,但表的初始化定义是否正确?初始化列表是扁平的,这不会引起警告吗?@StoryTeller其行为定义良好,没有问题尽管编译器通常会生成警告,并建议不要忽略嵌套大括号以提高可读性。在大多数情况下,完整的嵌套大括号确实可以提高可读性并使代码更清晰,但在这种情况下,它们不会。太好了!这是一个非常好的替代Lingxi的答案的方法,我们正在用简单性来交换r编译器检查和良好的编译警告。不过,我只能接受两个答案中的一个。@YSC如果凌西没有公布他的答案,我就不会想到我的答案,所以功劳应该归他。
    #include <iostream>
    #include <string>
    
    enum state {
      STATE_1,
      STATE_2,
      STATE_3,
      STATE_4,
      STATE_5,
      STATE_6,
      STATE_7,
      STATE_8,
    };
    
    state f(int a, bool b, const std::string& str) {
      static const state table[2][2][2] = {
        STATE_8, // 0, 0, 0
        STATE_7, // 0, 0, 1
        STATE_6, // 0, 1, 0
        STATE_5, // 0, 1, 1
        STATE_4, // 1, 0, 0
        STATE_3, // 1, 0, 1
        STATE_2, // 1, 1, 0
        STATE_1  // 1, 1, 1
      };
      return table[a < 0][b == false][str != "morning"];
    }
    
    int main() {
      std::cout << f(1, true, "morning") << std::endl;
    }
    
    #include <type_traits>
    
    namespace detail
    {
        constexpr std::size_t pack_bool(std::size_t result)
        {
            return result;
        }
    
        template<typename T, typename... Ts>
        constexpr std::size_t pack_bool(std::size_t result, T arg, Ts... args)
        {
            static_assert(std::is_same<bool, T>::value, "boolean expected");
            return pack_bool((result << 1) | arg, args...);
        }
    }
    
    template<typename T, typename... Ts>
    constexpr std::size_t pack_bool(T arg, Ts... args)
    {
        static_assert(std::is_same<bool, T>::value, "boolean expected");
        return detail::pack_bool(arg, args...);
    }
    
    #include <iostream>
    
    enum state
    {
        STATE_1,
        STATE_2,
        STATE_3,
        STATE_4,
        STATE_5,
        STATE_6,
        STATE_7,
        STATE_8,
    };
    
    state f(int a, bool b, const std::string& str)
    {
        switch (pack_bool(a >= 0, b == true, str == "morning"))
        {
            case pack_bool(false, false, false) : return STATE_1;
            case pack_bool(false, false, true)  : return STATE_2;
            case pack_bool(false, true,  false) : return STATE_3;
            case pack_bool(false, true,  true)  : return STATE_4;
            case pack_bool(true,  false, false) : return STATE_5;
            case pack_bool(true,  false, true)  : return STATE_6;
            case pack_bool(true,  true,  false) : return STATE_7;
            case pack_bool(true,  true,  true)  : return STATE_8;
        }
        return STATE_1;
    }
    
    int main()
    {
        std::cout << "State: " << f(1, true, "morning") << std::endl;
    }
    
    #include <iostream>
    #include <utility>
    #include <sstream>
    #include <string>
    
    namespace detail{
    
        template<size_t N> struct boolean_value;
        template<size_t N> using boolean_value_t = typename boolean_value<N>::type;
        template<size_t N> constexpr auto to_int(boolean_value_t<N> b) { return static_cast<int>(b); };
        template<size_t N> constexpr auto to_boolean_value(int i) { return static_cast<boolean_value_t<N>>(i); };
    
        template<> struct boolean_value<1> {
            enum type { bit0, bit1 };
        };
    
        template<> struct boolean_value<2> {
            enum type { bit00, bit01, bit10, bit11 };
        };
    
        template<> struct boolean_value<3> {
            enum type { bit000, bit001, bit010, bit011, bit100, bit101, bit110, bit111 };
        };
    
        template<class...Args, size_t...Is>
        static constexpr auto make_bitfield(std::tuple<Args...> t, std::index_sequence<Is...>)
        {
    #if __cplusplus > 201402L
            int accum = (0 | ... | (std::get<Is>(t) ? (1 << Is) : 0));
    #else
            int accum = 0;
            using expand = int[];
            (void) expand { (std::get<Is>(t) ? accum |= (1 << Is) : 0) ... };
    #endif
            return to_boolean_value<sizeof...(Is)>(accum);
        }
    
    }
    
    template<class...Args>
    constexpr
    auto mcase(Args&&...args)
    {
        return detail::make_bitfield(std::make_tuple(bool(std::forward<Args>(args))...),
                                     std::index_sequence_for<Args...>());
    }
    
    // little function to defeat the optimiser, otherwise clang inlines the whole program!
    auto get_result()
    {
        using namespace std;
    
        istringstream ss("foo 2");
        auto result = tuple<string, int>();
        ss >> get<0>(result) >> get<1>(result);
        return result;
    }
    
    int main()
    {
        using namespace std;
        const auto result = get_result();
        const auto& s1 = std::get<0>(result);
        const auto& v1 = std::get<1>(result);
    
        switch(mcase(s1 == "foo"s, v1 == 2))
        {
            case mcase(true, true):
                cout << mcase(true, true) << endl;
                break;
    
            case mcase(false, false):
                cout << mcase(false, false) << endl;
                break;
        }
        return 0;
    }
    
    ./mswitch.cpp:114:12: warning: enumeration values 'bit01' and 'bit10' not handled in switch [-Wswitch]
        switch(mcase(s1 == "foo"s, v1 == 2))
               ^
    1 warning generated.
    ./mswitch.cpp:114:12: warning: enumeration values 'bit01' and 'bit10' not handled in switch [-Wswitch]
        switch(mcase(s1 == "foo"s, v1 == 2))
               ^
    1 warning generated.
    
    3