隐式转换后发生C ++解除引用

时间:2018-05-08 09:53:00

标签: c++ language-lawyer implicit-conversion dereference

今天我看到当试图在函数调用中取消引用一个参数时,隐式转换发生在实际的解引用操作之前(我相信只有当原始类型不支持取消引用时)。

这种观察可以在这里看到:

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 ++标准是否明确提到了这种行为?谢谢。

1 个答案:

答案 0 :(得分:2)

让我们来看看这个表达式:

f(**static_cast<A*>(NULL))

从最里面到最外面,static_cast<A*>(NULL)A*(虽然更喜欢nullptrNULL,也更喜欢使用std::declval<A*>()来获取“类型为A*的东西”,而不是旧的空指针逼近方法。)

接下来,*(a prvalue of type A*)为您提供A类型的左值。这就是指针取消引用的含义,它不会过载。当事情易于推理时,这很好。

接下来,*(an lvalue of type A)。为了弄清楚这意味着什么,我们transform对函数符号的调用,以及我们的候选集合:

第一颗子弹找不到任何东西,没有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>
{ };