今天我看到当试图在函数调用中取消引用一个参数时,隐式转换发生在实际的解引用操作之前(我相信只有当原始类型不支持取消引用时)。
这种观察可以在这里看到:
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 ++标准是否明确提到了这种行为?谢谢。
答案 0 :(得分:2)
让我们来看看这个表达式:
f(**static_cast<A*>(NULL))
从最里面到最外面,static_cast<A*>(NULL)
是A*
(虽然更喜欢nullptr
到NULL
,也更喜欢使用std::declval<A*>()
来获取“类型为A*
的东西”,而不是旧的空指针逼近方法。)
接下来,*(a prvalue of type A*)
为您提供A
类型的左值。这就是指针取消引用的含义,它不会过载。当事情易于推理时,这很好。
接下来,*(an lvalue of type A)
。为了弄清楚这意味着什么,我们transform对函数符号的调用,以及我们的候选集合:
A::operator*()
operator*(a)
,在表达式的上下文中对operator*()
进行无限制查找。第一颗子弹找不到任何东西,没有A::operator*()
。第二个项目符号operator*()
上的无限制查找将找到函数C operator*(const C&);
,因为它在范围内。这是一个可行的候选人,因为A
可通过C
转换为C(A const&)
。第三个子弹没有可行的候选人。
因为我们只有一个可行的候选人,所以它通常是最有效的候选人 - 所以*(lvalue of type A)
为我们提供了C
类型的prvalue。
专门回答你的问题:
隐式转换发生在实际取消引用操作之前
是的,必须进行转换才能解决取消引用操作。虽然它实际上不是“解除引用”,但它只是一元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>
{ };