c++ - 如何在多个条件下分支/切换?

标签 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& 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;
}

最佳答案

可以在编译时在 POD 中嵌入一个 bool 值(条件结果)列表,然后在其上切换

用法:main.cpp

#include <iostream> /* std::cout */
#include "mswitch.h" /* mswitch, mcase */

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)
{
    mswitch(a >= 0, b == true, str == "morning")
    {
        mcase(false, false, false): return STATE_1;
        mcase(false, false, true) : return STATE_2;
        mcase(false, true, false) : return STATE_3;
        mcase(false, true, true)  : return STATE_4;
        mcase(true, false, false) : return STATE_5;
        mcase(true, false, true)  : return STATE_6;
        mcase(true, true, false)  : return STATE_7;
        mcase(true, true, true)   : return STATE_8;
    }
    return STATE_1;
}

int main()
{
    std::cout << "State: " << f(1, true, "morning") << std::endl;
}

语法糖:mswitch.h

#ifndef MSWITCH_GUARD_H
#define MSWITCH_GUARD_H

#include <initializer_list>
#include <cstddef>

namespace mswitch
{
    constexpr long long encode(long long value, size_t size) { return value << 6 | (0x3F & size); }

    class mswitch
    {
        std::initializer_list<bool> _flags;
    public:
        mswitch(std::initializer_list<bool> const& l) : _flags(l) {}
        operator long long() const
        {
            long long result = 0;
            size_t index = 0;
            for (bool b : _flags) {
                result |= b << index++;
            }
            return encode(result, _flags.size());
        }
    };

    template<bool head, bool... tail>
    struct mcase
    {
        constexpr mcase() = default;
        constexpr operator long long() const
        {
            return encode(tll(), 1+sizeof...(tail));
        }
        constexpr long long tll() const { return head | mcase<tail...>().tll() << 1; }
    };

    template<bool b>
    struct mcase<b>
    {
        constexpr mcase() = default;
        constexpr operator long long() const { return encode(tll(), 1); }
        constexpr long long tll() const { return b; }
    };
}

#define mswitch(head, ...) switch(mswitch::mswitch{head, __VA_ARGS__})
#define mcase(head, ...) case mswitch::mcase<head, __VA_ARGS__>()

#endif // MSWITCH_GUARD_H

编译 g++ -std=c++14 -O2 -Wall -pedantic main.cpp

工作原理

mswitchmcase 对象简单地构建(如果可能,在编译时,使用 constexpr 函数) bool 列表和之间的双射一个开关能够long long。由于 mcase 被赋予了编译时常量,因此所有 switch 标签本身实际上都是连续的编译时常量。

关于c++ - 如何在多个条件下分支/切换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34414983/

相关文章:

c++ - 无法在运行时找到共享对象。 KRPC

c++ - C++变量销毁

c++ - 与静态方法中的 decltype(*this) 等价?

c++ - std::async with std::unique 不编译

c++ - 如何在 eclipse makefile 项目的编译器选项中设置 -std=c++0x?

c++ - 模板化类,如何表示为另一个类的成员变量而不使此类模板化

c++ - 这些 shared_ptr 实例之间的区别?

c++ - 从 std::stringstream 中提取整个 std::string

c++ - 如果链接到未使用的库,可执行文件的构建是否不同?

c++ - 异常调用后是否保证 std::call_once 的线程通知