Разыменование C ++ происходит после неявного преобразования - PullRequest
0 голосов
/ 08 мая 2018

Сегодня я увидел, что при попытке разыменования аргумента в вызове функции неявное преобразование происходит перед фактической операцией разыменования (я верю, только если исходный тип не поддерживает разыменование).

Это наблюдение можно увидеть здесь:

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 голосов
/ 08 мая 2018

Давайте посмотрим на это выражение:

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

От самого внутреннего к самому внешнему, static_cast<A*>(NULL) - это A* (хотя предпочитают от nullptr до NULL, а также предпочитают использовать std::declval<A*>(), чтобы получить "что-то типа A*", а не старый подход приведения нулевого указателя).

Далее *(a prvalue of type A*) дает вам lvalue типа A. Вот что означает разыменование указателя, и оно не перегружается. Приятно, когда об этом легко рассуждать.

Далее *(an lvalue of type A). Чтобы выяснить, что это значит, мы преобразуем вызов функции-нотации, и наш набор кандидатов:

Первая пуля ничего не находит, A::operator*() нет. Второй пункт, неквалифицированный поиск по operator*(), найдет функцию C operator*(const C&);, потому что она находится в области видимости. Это приемлемый кандидат, потому что A конвертируется в C через C(A const&). Третья пуля не имеет жизнеспособного кандидата.

Поскольку у нас есть только один жизнеспособный кандидат, это тривиально лучший жизнеспособный кандидат, поэтому *(lvalue of type A) дает нам тип значения C.

Чтобы конкретно ответить на ваш вопрос:

неявное преобразование происходит до фактической операции разыменования

Да, преобразование должно произойти, чтобы разрешить операцию разыменования. Хотя на самом деле это не «разыменование», это просто унарный 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>
{ };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...