LValue ref квалифицированная функция-член, вызываемая для объекта RValue - PullRequest
4 голосов
/ 27 февраля 2020

Я пытаюсь выяснить, почему следующий фрагмент вызывает перегрузку оператора приведения LValue:

#include <iostream>

class Foo
{
public:
    Foo(int i = 0) : i(i) {}

    operator const int& () const &
    {
        std::cout << "lvalue\n";
        return i;
    }

    operator int () const &&
    {
        std::cout << "rvalue\n";
        return i;
    }

    int i = 0;
};

Foo Fool()
{
    return Foo(5);
}

int main()
{
    const int& i = Fool();
    const int j = Fool();

    return 0;
}

Токовые выходы:

lvalue

rvalue

Но из моего понимания Fool() возвращает rvalue, и поскольку const& может связываться с rvalues, нет необходимости создавать lvalue Foo.

Кто-нибудь может объяснить, почему lvalue строится? Я считаю, что это висячие lvalue.

1 Ответ

1 голос
/ 27 февраля 2020

Хорошо, поэтому следует отметить, что разрешение перегрузки учитывает только одну функцию преобразования для i. Они оба не участвуют, поэтому ссылочный классификатор нельзя использовать для их дифференциации. Для случая привязки ссылка

[over.match.ref]

При условиях, указанных в [dcl.init.ref], ссылка может быть привязан непосредственно к результату применения функции преобразования к выражению инициализатора. Разрешение перегрузки используется для выбора функции преобразования, которая будет вызвана. Предполагая, что «ссылка на cv1 T» - это тип инициализируемой ссылки, а «cv S» - это тип выражения инициализатора, а S - тип класса, функции-кандидаты выбираются следующим образом:

  • Рассматриваются функции преобразования S и его базовых классов. Те неявные функции преобразования, которые не скрыты в S и дают тип «lvalue ссылка на cv2 T2» (при инициализации lvalue ссылка или ссылка rvalue на функцию) или «cv2 T2» или «ссылка rvalue» к cv2 T2 »(при инициализации ссылки на rvalue или ссылки на lvalue на функцию), где« cv1 T »совместимо со ссылкой с« cv2 T2 », являются функциями-кандидатами. Для прямой инициализации те явные функции преобразования, которые не скрыты в S и дают тип «lvalue ссылка на cv2 T2» (при инициализации lvalue ссылка или ссылка rvalue на функцию) или «ссылка rvalue на cv2 T2 ”(при инициализации ссылки на rvalue или ссылки на lvalue на функцию), где T2 является тем же типом, что и T, или может быть преобразован в тип T с преобразованием квалификации, также являются функциями-кандидатами.

Согласно тексту, выделенному жирным шрифтом, при инициализации i наш только кандидат - operator int const&. Таким образом, разрешение перегрузки может либо пройти здесь, либо полностью потерпеть неудачу. Но он не может выбрать operator int, поскольку он даже не рассматривается. Это успешно, потому что квалифицированная константная ссылка lvalue может связываться с аргументом объекта.

С другой стороны, для инициализации значения

[over.match.conv]

При условиях, указанных в [dcl.init], в рамках инициализации объекта неклассового типа может быть вызвана функция преобразования для преобразования выражения инициализатора типа класса в тип инициализируемого объекта. Разрешение перегрузки используется для выбора функции преобразования, которая будет вызвана. Предполагая, что «cv1 T» - это тип инициализируемого объекта, а «cv S» - это тип выражения инициализатора, а S - тип класса, функции-кандидаты выбираются следующим образом:

  • Рассматриваются функции преобразования S и его базовых классов. Те неявные функции преобразования, которые не скрыты в S и дают тип T или тип, который можно преобразовать в тип T с помощью стандартной последовательности преобразования, являются функциями-кандидатами. Для прямой инициализации те функции явного преобразования, которые не скрыты в S и дают тип T или тип, который может быть преобразован в тип T с квалификационным преобразованием, также являются функциями-кандидатами. Считается, что функции преобразования, которые возвращают cv-квалифицированный тип, дают cv-неквалифицированную версию этого типа для этого процесса выбора функций-кандидатов. Вызов функции преобразования, возвращающей «ссылку на X», является glvalue типа X, и поэтому считается, что такая функция преобразования дает X для этого процесса выбора функций-кандидатов.

Таким образом, при инициализации j обе функции преобразования участвуют в качестве перегрузок, и здесь спецификатор ссылки имеет значение.

Вы получаете здесь свисающую ссылку, и, похоже, это связано с темным углом в языке. Пуля в первом цитируемом абзаце, вероятно, может быть уточнена, чтобы лучше рассмотреть привязку const lvlaue ссылок. Так как они могут также привязываться к временным файлам, ваш второй оператор преобразования в идеале мог бы быть кандидатом в соответствии с лучшими правилами.

...