C++ 为什么switch和if语句与转换运算符的行为不同?
为什么C++ 为什么switch和if语句与转换运算符的行为不同?,c++,if-statement,switch-statement,conversion-operator,explicit-conversion,C++,If Statement,Switch Statement,Conversion Operator,Explicit Conversion,为什么开关和如果语句与转换运算符的行为不同 struct WrapperA { explicit operator bool() { return false; } }; struct WrapperB { explicit operator int() { return 0; } }; int main() { WrapperA wrapper_a; if (wrapper_a) { /** this line compiles **/ }
开关
和如果
语句与转换运算符的行为不同
struct WrapperA
{
explicit operator bool() { return false; }
};
struct WrapperB
{
explicit operator int() { return 0; }
};
int main()
{
WrapperA wrapper_a;
if (wrapper_a) { /** this line compiles **/ }
WrapperB wrapper_b;
switch (wrapper_b) { /** this line does NOT compile **/ }
}
编译错误是
开关量不是整数
,而在if
语句中,它被完全识别为bool
。(GCC)语法是switch(condition)语句
条件-任何整数或枚举类型的表达式,或上下文可隐式转换为整数或枚举类型的类类型的表达式,或使用大括号或等于初始值设定项声明此类类型的单个非数组变量
取自
这意味着您只能对整数或枚举类型执行切换。要使编译器能够隐式地将包装器转换为整数/枚举类型,您需要删除explicit关键字:
显式说明符指定构造函数或转换函数(因为C++11)不允许隐式转换
您还可以将包装器强制转换为int类型
编辑地址@acraig5075备注:
您必须注意哪个运算符是显式的,哪个运算符是隐式的。如果两者都是隐式的,则代码将不会编译,因为会出现不一致性:
struct Wrapper
{
operator int() { return 0; }
operator bool() { return true; }
};
source_file.cpp:在函数“int main()”中:source_file.cpp:12:14:
错误:“包装器”的默认类型转换不明确
开关(w){
^source_file.cpp:12:14:注:候选转换
包括'Wrapper::operator int()'和'Wrapper::operator bool()'
消除歧义的唯一方法是进行强制转换
如果只有一个运算符是显式的,则将为switch语句选择另一个运算符:
#include <iostream>
struct Wrapper
{
explicit operator int() { return 0; }
operator bool() { return true; }
};
int main()
{
Wrapper w;
if (w) { /** this line compiles **/std::cout << " if is true " << std::endl; }
switch (w) {
case 0:
std::cout << "case 0" << std::endl;
break;
case 1:
std::cout << "case 1" << std::endl;
break;
}
return 0;
}
w
已隐式转换为1
(true
)(因为运算符int是显式的),并执行案例1
另一方面:
struct Wrapper
{
operator int() { return 0; }
explicit operator bool() { return true; }
};
输出:
if is true
case 0
w
已隐式转换为0
,因为运算符bool是显式的
在这两种情况下,if语句都是真的,因为w
在上下文中被计算为if语句中的布尔值。我认为这解释了为什么不接受开关
语句,而if
语句是:
在以下五种上下文中,如果声明bool t(e);
格式正确,则需要类型bool,并构建隐式转换序列。即显式用户定义的转换函数,如explicit t::operator bool()const;
被考虑。这样的表达式e被称为在上下文中可转换为bool
- 控制if、while、for的表达
- 逻辑运算符!、&&和| |
- 条件运算符?:
- 静态断言
- 不例外
您的代码有两个问题。
首先,转换运算符不能显式用于switch
语句。
其次,switch
条件需要整数类型,并且int
和bool
都是整数类型,因此存在歧义。
如果更改类以使其不存在这两个问题,开关将编译并按预期工作
另一个不需要更改类的解决方案是显式强制转换(static\u cast
可以)int
或bool的值一个答案是if
和switch
的行为不同,因为这就是标准的编写方式。另一个答案可能会推测标准为何以这种方式编写。好吧,我想标准是以if
语句的方式来处理规范的fic问题(隐式转换为bool
),但我想采用不同的观点
在if
语句中,条件必须是布尔值。并不是每个人都这样考虑if
语句,可能是因为语言中内置了各种便利。然而,在其核心,一个if
语句需要知道“做这个”或“做那个”;“是”或“否”true
或false
——即布尔值。在这方面,将某物放入语句的条件中是明确要求将某物转换为bool
另一方面,switch
语句接受任何整数类型。也就是说,没有任何一种类型比所有其他类型更受欢迎。使用switch
可以被视为将值转换为整数类型的显式请求,但不一定特定地转换为int
。因此,使用convrsion到int
,当需要显式请求特定的转换时。声明转换运算符explicit
的存在是为了防止隐式转换到该类型。这就是它的目的。switch
尝试隐式将其参数转换为整数;因此explicit
运算符不会被调用。这是预期的行为
出乎意料的是,在if
情况下调用了显式操作符,从而挂起了一个故事
请参阅,根据上述规则,通过if
使类型可测试的方法是将非显式
转换为bool
。问题是…bool
是一个有问题的类型。它可以隐式转换为整数。因此,如果您使类型隐式转换为bool
,这就是法律代码:
void foo(int);
foo(convertible_type{});
但这也是毫无意义的代码。您从未打算将convertible\u type
隐式转换为整数。您只是想将其转换为布尔值以进行测试
在C++11之前,解决这个问题的方法是“安全布尔习惯用法”,这是一个复杂的痛苦和挑战
void foo(int);
foo(convertible_type{});