(涉及显式)运算符和构造函数转换的优先级
(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_cast
是 direct initialization, while passing an argument to a function is copy initialization。除其他事项外,复制初始化从不使用显式构造函数。另一件需要注意的事情是,直接初始化 需要 使用 类 的构造函数(显式或非显式)。虽然这并不意味着转换不能执行直接初始化:它可以用于转换构造函数的参数,如果构造函数是 compiler-generated 副本,那么它会 看起来 就像转换函数执行了直接初始化(而实际上它是由复制构造函数执行的)。尝试声明一个复制构造函数而不定义它(disable-copy 技术),你会发现转换函数在直接初始化上下文中不再有效:它会编译,但会导致链接错误。
考虑到这一点:
- 显而易见。
- 直接初始化需要构造函数,所以调用。
- 显而易见。
- 真的和2一样。声明转换函数
explicit
只会防止它被隐式调用,不会强制在显式上下文中使用它。
- 显而易见。
- 同样,直接初始化需要一个构造函数,它允许使用显式构造函数。
- 显而易见。
- 另一种直接初始化的情况。
我浏览了很多与转换相关的问题,但其中 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_cast
是 direct initialization, while passing an argument to a function is copy initialization。除其他事项外,复制初始化从不使用显式构造函数。另一件需要注意的事情是,直接初始化 需要 使用 类 的构造函数(显式或非显式)。虽然这并不意味着转换不能执行直接初始化:它可以用于转换构造函数的参数,如果构造函数是 compiler-generated 副本,那么它会 看起来 就像转换函数执行了直接初始化(而实际上它是由复制构造函数执行的)。尝试声明一个复制构造函数而不定义它(disable-copy 技术),你会发现转换函数在直接初始化上下文中不再有效:它会编译,但会导致链接错误。
考虑到这一点:
- 显而易见。
- 直接初始化需要构造函数,所以调用。
- 显而易见。
- 真的和2一样。声明转换函数
explicit
只会防止它被隐式调用,不会强制在显式上下文中使用它。 - 显而易见。
- 同样,直接初始化需要一个构造函数,它允许使用显式构造函数。
- 显而易见。
- 另一种直接初始化的情况。