C++ 如何在多个条件下进行分支/切换?
有没有一种方法可以在多个条件下进行分支,而不编写看起来一团糟的代码?最好使用C++11或C++14中的合成糖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
#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