【问题标题】:Why doesn't explicit bool() conversion happen in contextual conversion为什么在上下文转换中不发生显式 bool() 转换
【发布时间】:2014-03-30 15:30:55
【问题描述】:

如果下面的测试程序

#include <iostream>

class A {
public:
    A() {}
    explicit operator bool() const {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
        return true;
    }
//    explicit operator bool() {
//        std::cout << __PRETTY_FUNCTION__ << std::endl;
//        return true;
//    }
    const operator int() const {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
        return 1;
    }
    operator int() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
        return 1;
    }
};

int main() {
    A a;
    if (a) {
        std::cout << "bool()" << std::endl;
    }
    if (a + 0) {
        std::cout << "int()" << std::endl;
    }
}

运行,输出为

int A::operator int()
bool()
int A::operator int()
int()

而不是

bool A::operator _Bool()
bool()
int A::operator int()
int()

我的预期(以及如果您取消注释注释部分会得到什么)。

那么问题是,转换为非 const-int 优先于转换为 const-bool 的规则是什么?

【问题讨论】:

  • 哪个编译器? const operator int() const 应该编译失败
  • 编译器是clang-3.4
  • 您能否更新问题标题以删除双重否定。我会自己做,但我不确定是否删除“不”或“不”。或者两者兼而有之?
  • 好的,刚刚清除了标题。谢谢!

标签: c++ c++11 operator-overloading


【解决方案1】:

在对引用绑定执行重载决议时,首选 cv 限定的类型。这在 13.3.3.2p3 中进行了讨论,并给出了示例:

struct X {
  void f() const;
  void f();
};
void g(const X& a, X b) {
  a.f(); // calls X::f() const
  b.f(); // calls X::f()
}

请注意,将对象绑定到成员函数 (13.3.1.1.1p2) 的隐式对象参数是引用绑定 (13.3.3.1.4)。

出于重载决议 (13.3p2) 的目的,转换运算符被视为成员函数 (13.3.1.5)。到bool 的上下文转换具有初始化(4p4)的语义。

重要的是,转换运算符的返回类型所需的任何转换仅在考虑到转换运算符本身之间的重载决议(13.3.3p1)之后才考虑

解决方案是确保所有转换运算符具有相同的const-qualification,尤其是对于标量类型。

【讨论】:

  • “重要的是,转换运算符的返回类型所需的任何转换只有在考虑了转换运算符本身之间的重载解决方案(13.3.3p1)之后才会考虑。” 嗯,有以“上下文是用户定义转换的初始化” 开头的项目符号似乎暗示这是完全有意的。 +1
  • @dyp 这里没有 UDCS,因为我们没有使用 X 参数在不同的函数之间进行解析。如果我们有 f(bool); f(float); X x; f(x); 就会有 UDCS,而且这些 UDCS 确实是模棱两可的。
  • Abool 的整个转换是一个 UDCS(在 OP 的示例中),但仍然“过早”应用重载解决方案恕我直言,UDC 需要从 @ 转换不考虑 987654328@ 到 bool,而仅用于定义可行函数(因此仅考虑隐含对象参数的 SCS 用于重载解析)。
  • 嗯,您的示例可能是 reason 为什么转换函数的重载解析发生这么早:如果上下文是对重载函数的调用(而不像在 OP ,具有固定目标类型的转换),需要执行两个重载解决步骤:1. 选择转换函数 2. 选择f 的重载。
【解决方案2】:

转换为非 const-int 优先于转换为 const-bool 的规则是什么?

使用非常量对象的常量成员函数,需要将非常量对象转换为常量对象。这就是为什么operator int()operator bool() const 更匹配的原因。

为了更清楚一点,如果您要删除 int 运算符,第一个 bool 上下文(第一个 if)真正发生的情况是:

if ( const_cast<const A&>(a).operator bool() ) {

相反,发生的事情是这样的:

if ( a.operator int() )

【讨论】:

  • 这个答案并没有真正奏效,因为 OPs 问题中的注释运算符也是明确的,并且仅仅因为 const 而改变了行为。此外,显式 operator bool 可以在不转换为布尔上下文(例如 if)的情况下使用。这是在 C++11 中实现安全布尔惯用语的一种非常简单的方法。
  • 因此,要正确使用 c++11 中的显式布尔惯用语,必须同时实现运算符 bool() 的 const 和非 const 版本。只是为了防止其他转换运算符介入?
  • 我不太明白这种重载解决方案的排名是如何发生的。通常,将一些A 绑定到A const&amp; 是直接引用绑定,因此被认为是精确匹配。因此,隐含对象参数在两种情况下都应与隐含对象参数完全匹配。然后,两者都有一个 UDC,但是对于到 int 的转换,接下来是布尔转换。显然,这不是编译器中发生的事情,隐含对象参数的匹配以某种方式排名不同..
  • @wimalopaan 要么,要么只实现转换运算符的 const 版本。
  • @dyp 我试图找出标准中的哪个段落是重要的。我认为它是 [conv.quel],但它谈论的是指针——而不是引用。它仍然需要从左值转换为纯右值才能调用operator bool() const,使operator int() 更合格。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多