C++ Primer 5th Edition Глава 16.5 Специализации шаблонов классов

Я думаю, что книга содержит ошибку на странице 711:

В § 16.2.3 (стр. 684) мы представили библиотеку remove_referenceтип. Этот шаблон работает через ряд специализаций:

       // original, most general template
template <class T> struct remove_reference {
    typedef T type;
};
// partial specializations that will be used fore lvalue and rvalue references
template <class T> struct remove_reference<T&> // lvalue references
    typedef T type;
};
template <class T> struct remove_reference<T&&> // rvalue references
    typedef T type;
};

...

       int i;
// declyptype(42) is int, used the original template
remove_reference<decltype(42)>::type a;
// decltype(i) is int&, uses first(T&) partial specialization
remove_reference<decltype(i)>::type b;
// delctype(std::move(i)) is int&&, uses second (i.e., T&&) partial specialization
remove_reference<decltype(std::move(i))>::type c;

Все три переменные, a,,а также c, есть тип .

Я думаю decltype(i)дает равнину intи не int&поэтому наиболее общий шаблон используется на самом деле в случае b. Для простых типов переменных [ 1]decltypeспецификатор типа дает простые типы и для других выражений, которые могут использоваться как lvalueэто даст и lvalue reference.

Пример

      #include <iostream>
#include <string>
#include <typeinfo>
using namespace std;

template <typename T> struct blubb {
    typedef T type;
    void print() { cout << "plain argument type\n"; }
};

template <typename T> struct blubb<T&> {
    typedef T type;
    void print() { cout << "lvalue reference type\n"; }
};

template <typename T> struct blubb<T&&> {
    typedef T type;
    void print() { cout << "rvalue reference type\n"; }
};

int main() {
    int i = 0;

    blubb<decltype(42)> plain;
    plain.print();
    blubb<decltype(i)> lvalue_ref; // actually not!
    lvalue_ref.print();
    
    int* pi = &i;
    blubb<decltype(*pi)> lvalue_ref2; // expression which can be on the left hand side
    lvalue_ref2.print();

    blubb<decltype(std::move(i))> rvalue_ref;
    rvalue_ref.print();

    return 0;
}

Скомпилируйте и запустите

      g++ -o types types.cpp -Wall -pedantic -g && ./types
plain argument type
plain argument type
lvalue reference type
rvalue reference type

Пожалуйста, скажите мне, прав я или нет, и объясните, если это уместно.
Спасибо

[1] Вероятно, правильный термин id-expression?

1 ответ

Да, для выражения id без скобок,выдает тип объекта, названный id-выражением, затем decltype(i)дает тип int.

  1. Если аргумент является id-выражением без скобок или выражением доступа к члену класса без скобок, то decltypeдает тип объекта, названного этим выражением.

С другой стороны, decltype((i))дает тип int&; (i)обрабатывается как выражение lvalue.

  1. Если аргумент является любым другим выражением типа T, и
    б) если категория значения выражения lvalue, то decltype дает T&;

Обратите внимание, что если имя объекта заключено в круглые скобки, оно рассматривается как обычное выражение lvalue, поэтому decltype(x)и decltype((x))часто бывают разных типов.

Другие вопросы по тегам