不同的转换运算符由不同的编译器调用 [英] Different cast operator called by different compilers

查看:108
本文介绍了不同的转换运算符由不同的编译器调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下简短的C ++程序:

  #include< iostream& 

class B {
public:
operator bool()const {
return false;
}
};

class B2:public B {
public:
operator int(){
return 5;
}
};

int main(){
B2 b;
std :: cout<< std :: boolalpha< (bool)b < std :: endl;
}



如果我在不同的编译器上编译它,我得到不同的结果。使用Clang 3.4和GCC 4.4.7它打印 true ,而Visual Studio 2013打印 false ,这意味着他们调用不同的操作符在(bool)b 。根据标准,这是正确的行为?



在我的理解运算符bool()不需要转换,而 operator int()需要 int bool 转换,所以编译器应该选择第一个。 const 执行某些操作,编译器认为const转换更昂贵?



删除 const ,所有编译器同样会生成 false 作为输出。
另一方面,如果我将两个类组合在一起(两个操作符将在同一个类中),所有三个编译器将产生 true 输出。

解决方案

标准状态:


函数在派生类中不隐藏基类中的转换函数,除非这两个函数转换为相同类型。



§12.3[class.conv]


这意味着运算符bool 未被



标准规定:




§13.3.3.1[over.match.funcs]




在这种情况下,隐含对象参数是 b ,类型为 B2& operator bool 需要 const B2& ,因此编译器必须将const添加到 b 调用 operator bool 。 - 所有其他条件相同 - 使 operator int 更好地匹配。



static_cast (在这种情况下,C风格的转换正在执行)可以转换为 T int )if:


声明 T t对于一些发明的临时变量 t



§5.2.9[expr.static.cast]


因此 int 可以转换为 bool ,并且 bool 也可以转换为 bool



标准状态:


考虑 S 的函数及其基类。那些不隐藏在 S 和yield类型 T 中的非显式转换函数,通过标准转换序列转换为 T 类型是候选函数。



§13.3.1.5 [over.match.conv]


因此,重载集包括 operator int operator bool 。所有其他条件相同, operator int 是更好的匹配(因为你不必添加constness)。因此,应该选择 operator int



请注意(可能反对直觉)标准不考虑返回类型(即这些操作符转换的类型),一旦它们已经被添加到重载集合(如上所述),假设其中一个的参数的转换序列优于另一个的参数的转换序列(其



标准状态:

$ b $给定这些定义,可行函数F1被定义为比另一个可行函数F2更好的函数,如果对于所有自变量i,ICSi(F1)不是比ICSi(F2)更差的转换序列, p>


  • 对于某个参数j,ICSj(F1)是比ICSj(F2)更好的转换序列,否则

  • 上下文是通过用户定义的转换的初始化,从F1的返回类型到目标类型(即,被初始化的实体的类型)的标准转换序列是比



§13.3.3[over.match.best]


在这种情况下,只有一个参数(隐式 this 参数)。 B2& => B2& (调用 operator int )优于 B2& => const B2& c $ c> operator bool ),因此从重载集合中选择 operator int ,而不考虑它实际上不转换的事实直接到 bool


Consider the following short C++ program:

#include <iostream>

class B {
public:
    operator bool() const {
        return false;
    }
};

class B2 : public B {
public:
    operator int() {
        return 5;
    }
};

int main() {
    B2 b;
    std::cout << std::boolalpha << (bool)b << std::endl;
}

If I compile it on different compilers, I get various results. With Clang 3.4 and GCC 4.4.7 it prints true, while Visual Studio 2013 prints false, which means that they call different cast operators at (bool)b. Which is the correct behavior according to the standard?

In my understanding operator bool() needs no conversion, while operator int() would require an int to bool conversion, so the compiler should choose the first one. Does const do something with that, is const-conversion considered more "expensive" by the compiler?

If I remove the const, all compilers equally produce false as output. On the other hand, if I combine the two classes together (both operators will be in the same class) all three compilers will produce true output.

解决方案

The standard states:

A conversion function in a derived class does not hide a conversion function in a base class unless the two functions convert to the same type.

§12.3 [class.conv]

Which means that operator bool is not hidden by operator int.

The standard states:

During overload resolution, the implied object argument is indistinguishable from other arguments.

§13.3.3.1 [over.match.funcs]

The "implied object argument" in this case is b, which is of type B2 &. operator bool requires const B2 &, so the compiler will have to add const to b to call operator bool. This -- all other things being equal -- makes operator int a better match.

The standard states that a static_cast (which the C-style cast is performing in this instance) can convert to a type T (in this case int) if:

the declaration T t(e); is well-formed, for some invented temporary variable t.

§5.2.9 [expr.static.cast]

Therefore the int may be converted to a bool, and a bool may equally be converted to a bool.

The standard states:

The conversion functions of S and its base classes are considered. Those non-explicit conversion functions that are not hidden within S and yield type T or a type that can be converted to type T via a standard conversion sequence are candidate functions.

§13.3.1.5 [over.match.conv]

So the overload set consists of operator int and operator bool. All other things being equal, operator int is a better match (since you don't have to add constness). Therefore operator int should be selected.

Note that (perhaps against intuition) the standard does not consider the return type (i.e. the type to which these operators convert) once they have been added to the overload set (as established above), provided the conversion sequence for the arguments of one of them is superior to the conversion sequence for the arguments of the other (which, due to constness, is the case in this instance).

The standard states:

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then

  • for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,
  • the context is an initialization by user-defined conversion and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type of F2 to the destination type.

§13.3.3 [over.match.best]

In this case, there is only one argument (the implicit this parameter). The conversion sequence for B2 & => B2 & (to call operator int) is superior to B2 & => const B2 & (to call operator bool), and therefore operator int is selected from the overload set without regard to the fact that it actually doesn't convert directly to bool.

这篇关于不同的转换运算符由不同的编译器调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆