(涉及显式)运算符和构造函数转换的优先级

(involving explicit)Precedence with operator and constructor conversion

我浏览了很多与转换相关的问题,但其中 none 似乎是在以这种方式讨论显式关键字。 这是代码:

struct B;
struct A{
    /*explicit*/ A(const B&){ cout << 1; }  // *1
};
struct B{
    /*explicit*/ operator A()const{ cout << 2; } // *2
};

void foo(const A &){}

int main(void){
    B b;
    foo( /*static_cast<A>*/ (b) ); // *3
}

结果:(Y:未注释,N:commented,X:任一)

# | *1 | *2 | *3 |output|  
1 |  N |  N |  N |error |
2 |  N |  N |  Y |  1   |
3 |  N |  Y |  N |  1   |
4 |  N |  Y |  Y |  1   |
5 |  Y |  N |  N |  2   |
6 |  Y |  N |  Y |  1   |
7 |  Y |  Y |  N |error |
8 |  Y |  Y |  Y |  1   |

1、7为错误,属于正常现象(有歧义,无法自动转换)
2 好像构造函数有更高的优先级,但是为什么?
3、5很容易理解。
4 很奇怪,因为它没有调用显式的。为什么?
6 可能是由于 'explicit' 或具有更高优先级的构造函数。是哪一个原因? 8 似乎构造函数具有更高的优先级,但为什么?

有人可以提供一些解释吗?谢谢!

一个很好的问题。

首先,explicit 并不意味着 "this has precedence if explicit conversion is required"。意思是"this thing can only be invoked explicitly"。所以它创造了一些不能调用它的情况,而不是强制在其他情况下调用它。

另一件需要考虑的事情是 static_castdirect initialization, while passing an argument to a function is copy initialization。除其他事项外,复制初始化从不使用显式构造函数。另一件需要注意的事情是,直接初始化 需要 使用 类 的构造函数(显式或非显式)。虽然这并不意味着转换不能执行直接初始化:它可以用于转换构造函数的参数,如果构造函数是 compiler-generated 副本,那么它会 看起来 就像转换函数执行了直接初始化(而实际上它是由复制构造函数执行的)。尝试声明一个复制构造函数而不定义它(disable-copy 技术),你会发现转换函数在直接初始化上下文中不再有效:它会编译,但会导致链接错误。

考虑到这一点:

  1. 显而易见。
  2. 直接初始化需要构造函数,所以调用。
  3. 显而易见。
  4. 真的和2一样。声明转换函数 explicit 只会防止它被隐式调用,不会强制在显式上下文中使用它。
  5. 显而易见。
  6. 同样,直接初始化需要一个构造函数,它允许使用显式构造函数。
  7. 显而易见。
  8. 另一种直接初始化的情况。