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{});