"We do not use const rvalue references" Really?

В заголовке цитата из B.Stroustrup "The C++ Programming Language" (Fourth edition) (7.7.2 Rvalue References)

Посмотрим, как это выглядит в действительности.

Если заглянуть в драфт последнего стандарта, в раздел 7.3.1 Преобразование lvalue-to-rvalue
то мы увидим следующее:

A glvalue ([basic.lval]) of a non-function, non-array type T can be converted to a prvalue.[...]
If T is a non-class type, the type of the prvalue is the cv-unqualified version of T. Otherwise, the type of the prvalue is T.

 Что значит "cv-unqualified"? Опять посмотрим в стандарте:

Each type which is a cv-unqualified complete or incomplete object type or is void ([basic.types]) has three corresponding cv-qualified versions of its type: a const-qualified version, a volatile-qualified version, and a const-volatile-qualified version.
 [...]


    The cv-qualified or cv-unqualified versions of a type are distinct types; however, they shall have the same representation and alignment requirements.

    Итак, вернемся к rvalue. Да, в С rvalue никогда не имели cv-квалификаторов. Только lvalue. С другой стороны, rvalue для классов могут иметь cv-квалификаторы, а встроенные типы (подобные int) не могут. Посмотрим пример


    class A {
    public:
        void foo() const { std::cout << "A::foo() const\n"; }
        void foo() { std::cout << "A::foo()\n"; }
    };

    A bar() { return A(); }
    const A cbar() { return A(); }

    int main()
    {
        bar().foo();  // calls foo
        cbar().foo(); // calls foo const
    }

    Функция bar() возвращает rvalue на А, а функция cbar() возвращает const rvalue на А. Этот факт подтверждается вызовом соответственно неконстантной и константной версий функции foo().

    Программа выводит

    A::foo()
    A::foo() const

    При отсутствии константной версии foo() мы получаем ошибку при компиляции (GCC 8.2.0):

    prog.cc: In function 'int main()':
    prog.cc:16:16: error: passing 'const A' as 'this' argument discards qualifiers [-fpermissive]
         cbar().foo(); // calls foo const
                    ^
    prog.cc:6:10: note:   in call to 'void A::foo()'
         void foo() { std::cout << "A::foo()\n"; }

    После изменения примера для возврата rvalue на примитивный тип

    #include <iostream>

    int bar() { return int(); }
    const int cbar() { return int(); }

    int main()
    {
        bar();  
        cbar(); 
    }

    получаем предупреждение компилятора

    prog.cc:4:1: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
     const int cbar() { return int(); }
     ^~~~~


    Использована статья Eli Bendersky

    Комментарии

    Популярные сообщения из этого блога

    Полезные новации С++17. Выражения свертки (Fold expressions)

    Перегрузка и специализация шаблонных функций.

    Поддержка декомпозиции при объявлении (structural bindings) для классов