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
.
- Если аргумент является id-выражением без скобок или выражением доступа к члену класса без скобок, то
decltype
дает тип объекта, названного этим выражением.
С другой стороны,
decltype((i))
дает тип
int&
;
(i)
обрабатывается как выражение lvalue.
- Если аргумент является любым другим выражением типа
T
, и
б) если категория значения выражения lvalue, то decltype даетT&
;
Обратите внимание, что если имя объекта заключено в круглые скобки, оно рассматривается как обычное выражение lvalue, поэтому
decltype(x)
иdecltype((x))
часто бывают разных типов.