C++ 取消引用发生在隐式转换之后
C++ dereference happens after implicit conversion
今天我看到当试图在函数调用中取消引用参数时,隐式转换发生在实际取消引用操作之前(我相信只有原始类型不支持取消引用)。
可以在这里看到这个观察结果:
struct A{};
struct C
{
C(const A&)
{
}
};
C operator*(const C&);
double f(C);
template <typename T>
struct t
{
static const bool value = sizeof(f(**static_cast<T*>(NULL))) == sizeof(double);
};
int main(int argc, const char * argv[]) {
t<A>::value;
}
C++ 标准是否明确提及此行为?谢谢。
让我们看一下这个表达式:
f(**static_cast<A*>(NULL))
从最里面到最外面,static_cast<A*>(NULL)
是一个 A*
(尽管更喜欢 nullptr
而不是 NULL
,并且也更喜欢使用 std::declval<A*>()
获得 "something of type A*
" 而不是旧的空指针方法转换)。
接下来,*(a prvalue of type A*)
给你一个 A
类型的左值。这就是指针取消引用的意思,它是不可重载的。当事情很容易推理时,这很好。
接下来,*(an lvalue of type A)
。为了弄清楚这意味着什么,我们 transform 对函数符号的调用,我们的候选集是:
A::operator*()
operator*(a)
,在表达式的上下文中对 operator*()
进行非限定查找。
- built-in 位候选人。
第一个子弹没找到,没有A::operator*()
。第二个项目符号 operator*()
上的非限定查找将找到函数 C operator*(const C&);
,因为它在范围内。它是一个可行的候选者,因为 A
可以通过 C(A const&)
转换为 C
。第三颗子弹没有可行的候选者。
因为我们只有一个可行的候选者,所以它是最好的可行候选者 - 所以 *(lvalue of type A)
给了我们一个 C
.
类型的纯右值
具体回答你的问题:
the implicit conversion happens before the actual dereference operation
是的,必须进行转换才能解决取消引用操作。虽然它实际上不是 "dereference",但它只是一个一元 operator*()
。
最后,f(prvalue of type C)
调用我们拥有的那个 f
给我们 double
。
请注意,在现代 C++ 中,我建议将检查编写为更接近于:
template <typename T>
struct t
: std::is_same<
decltype(f(*std::declval<T>())), // <== the type we get when we call f
// on a dereferenced T
double>
{ };
今天我看到当试图在函数调用中取消引用参数时,隐式转换发生在实际取消引用操作之前(我相信只有原始类型不支持取消引用)。
可以在这里看到这个观察结果:
struct A{};
struct C
{
C(const A&)
{
}
};
C operator*(const C&);
double f(C);
template <typename T>
struct t
{
static const bool value = sizeof(f(**static_cast<T*>(NULL))) == sizeof(double);
};
int main(int argc, const char * argv[]) {
t<A>::value;
}
C++ 标准是否明确提及此行为?谢谢。
让我们看一下这个表达式:
f(**static_cast<A*>(NULL))
从最里面到最外面,static_cast<A*>(NULL)
是一个 A*
(尽管更喜欢 nullptr
而不是 NULL
,并且也更喜欢使用 std::declval<A*>()
获得 "something of type A*
" 而不是旧的空指针方法转换)。
接下来,*(a prvalue of type A*)
给你一个 A
类型的左值。这就是指针取消引用的意思,它是不可重载的。当事情很容易推理时,这很好。
接下来,*(an lvalue of type A)
。为了弄清楚这意味着什么,我们 transform 对函数符号的调用,我们的候选集是:
A::operator*()
operator*(a)
,在表达式的上下文中对operator*()
进行非限定查找。- built-in 位候选人。
第一个子弹没找到,没有A::operator*()
。第二个项目符号 operator*()
上的非限定查找将找到函数 C operator*(const C&);
,因为它在范围内。它是一个可行的候选者,因为 A
可以通过 C(A const&)
转换为 C
。第三颗子弹没有可行的候选者。
因为我们只有一个可行的候选者,所以它是最好的可行候选者 - 所以 *(lvalue of type A)
给了我们一个 C
.
具体回答你的问题:
the implicit conversion happens before the actual dereference operation
是的,必须进行转换才能解决取消引用操作。虽然它实际上不是 "dereference",但它只是一个一元 operator*()
。
最后,f(prvalue of type C)
调用我们拥有的那个 f
给我们 double
。
请注意,在现代 C++ 中,我建议将检查编写为更接近于:
template <typename T>
struct t
: std::is_same<
decltype(f(*std::declval<T>())), // <== the type we get when we call f
// on a dereferenced T
double>
{ };