путаница, перегружающая функции-члены для rvalue и lvalues

У меня есть следующая установка:

struct foo
{
    void bar( ) &  { std::cout << "lvalue\n"; }
    void bar( ) && { std::cout << "rvalue\n"; }

    ~foo( ) { bar( ); }
};


int main( int arg, char **argv )
{
    foo{ }.bar();
}

что приводит к выводу

rvalue
lvalue

Я не понимаю вывод dtor, который всегда равен lvalue, как бы я ни старался. Хотя я согласен с тем, что адрес, аналогичный

(*this).bar( ); // sure enough this will print lvalue

вызывает lvalue-overload. Я не понимаю, почему я никогда не могу получить вывод rvalueдля dtor.

Я нахожу это странным, поскольку объект сначала является rvalue и каким-то образом привязывается к lvalue перед уничтожением. В чем тут дело?


person david    schedule 22.06.2016    source источник
comment
Вы пропускаете отслеживание конструкторов.   -  person    schedule 22.06.2016


Ответы (1)


this — это prvalue, а *this — это lvalue, естественно, он вызовет ref-квалификаторы lvalue:

§ 5.3.1 Unary operators [expr.unary.op]

Унарный оператор * выполняет косвенность: выражение, к которому он применяется, должно быть указателем на тип объекта или указателем на тип функции, а результатом является lvalue. ссылаясь на объект или функцию, на которую указывает выражение.

Из cppreference этот указатель:

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

Примечание: вызов this-> эквивалентен вызову (*this).

#include <iostream>

struct foo
{
    void bar( ) &  { std::cout << "lvalue\n"; x(); }
    void bar( ) && { std::cout << "rvalue\n"; x(); }

    void x( ) & { std::cout << "x lvalue\n"; }
    void x( ) && { std::cout << "x rvalue\n"; }

    ~foo( ) { bar( ); }
};


int main( int arg, char **argv )
{
    foo{ }.bar();
}

Отпечатки:

rvalue
x lvalue
lvalue
x lvalue

Если по какой-то причине вы действительно хотите вызвать функцию rvalue, вы можете привести указатель this к ссылке rvalue:

~foo( ) { static_cast<foo&&>(*this).bar( ); }

Или используя std::move:

~foo( ) { std::move(*this).bar( ); }
person hlscalon    schedule 22.06.2016
comment
спасибо за разработку. означает ли это, что в контексте, где разрешено this (что в основном во всех функциях-членах, включая ctor и dtor), объект будет рассматриваться как lvalue, в то время как внешняя категория значений может быть другой? (проголосовал, но пока не имеет достаточного количества представителей). - person david; 22.06.2016
comment
@Давид Да. Простое использование этого, явно или неявно, вызовет lvalue ref-qualifiers. Добавлено решение для вызова квалификаторов rvalue ref. - person hlscalon; 22.06.2016
comment
нет - я не хочу принудительно вызывать rvalue-overload. Я просто был сбит с толку тем, что объект оказался rvalue, и клиентский код выдаст этот вывод. dtor, однако, сказал lvalue, что показалось мне странным, поскольку один и тот же объект был rvalue и lvalue в зависимости от того, вызывалась ли функция-член - person david; 22.06.2016
comment
спасибо за уточнение! какой-либо способ пересылки «внешней» категории значений? (просто интересно, пока нет варианта использования, возможно, там использовалась бы функция, не являющаяся членом). - person david; 22.06.2016