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



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

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:注释,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可能是由于"显式"或构造函数具有更高的优先级。哪一个是原因?8似乎构造函数有更高的优先级,但为什么呢

有人能解释一下吗?谢谢

一个非常好的问题。

首先,explicit并不意味着"如果需要显式转换,它就有优先权"。它的意思是"这个东西只能显式调用"。因此,它创建了一些无法调用的情况,而不是在其他情况下强制调用它。

另一件需要考虑的事情是static_cast是直接初始化,而将参数传递给函数是复制初始化。除其他外,复制初始化从不使用显式构造函数。另一件需要注意的事情是,直接初始化需要使用类的构造函数(显式或非显式)。尽管这并不意味着转换不能执行直接初始化:它可以用于转换构造函数的参数,如果构造函数是编译器生成的副本,那么它看起来就像转换函数执行的直接初始化一样(而事实上它是由副本构造函数执行的)。尝试在不定义复制构造函数的情况下声明它(禁用复制技术),您将看到转换函数不再在直接初始化上下文中工作:它将进行编译,但会导致链接错误。

考虑到这一点:

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

最新更新