auto
auto
прост: он даст тот же тип, что и вычет параметра шаблона по значению.auto
равномерно работает с выражениями.
template <class T>
void deduce(T x);
int &refint();
std::string str();
std::string const conststr();
auto i1 = 1; // deduce(1) gives T=int so int i1
auto i2 = i1; // deduce(i1) gives T=int so int i2
auto i3 = refint(); // deduce(refint()) gives T=int so int i3
const auto ci1 = i1; // deduce(i1) gives T=int so const int ci1
auto i4 = ci1; // deduce(ci1) gives T=int so int i4
auto s1 = std::string(); // std::string s1
auto s2 = str(); // std::string s2
auto s3 = conststr(); // std::string s3
В C ++ выражения не могут иметь ссылочный тип (refint()
имеет тип int
, а не int&
).
Обратите внимание, что lvalueness ofВыражение не является проблемой для выражения справа (справа от знака равенства или чего-то, что копируется в целом).Rvalue 1
обрабатывается как lvalue i1
и refint()
.
Для параметров по значению (то есть, не ссылочных параметров) применяется не только преобразование lvalue в rvalue, но и массив дляпреобразование указателя.const игнорируется.
decltype
decltype
- очень полезная функция с ужасным интерфейсом:
decltype
действует по-разному в некоторых выражениях, определенных в терминахпоиск имени и другие выражения!Это тот тип функций, который заставляет людей ненавидеть C ++.
decltype
чего-то с именем
decltype(entity)
будет выполнять поиск имени и сообщать объявленный тип сущности.(entity
может быть неквалифицированным или квалифицированным идентификатором или доступом к члену, например expr.identifier
.)
decltype(f(args))
выполнит поиск имени и разрешение перегрузки и даст объявленный тип возврата функции, а невведите выражение:
extern decltype(refint()) ri1; // int &ri1
Так что теперь я могу проверить свое понимание языка с помощью decltype
:
template <class T, class U>
struct sametype {};
template <class T>
struct sametype<T,T> {typedef int same;};
sametype<T,U>::same
существует тогда T
и U
точно такого же типа.
sametype<decltype (i1), int>::same check_i1;
sametype<decltype (i2), int>::same check_i2;
sametype<decltype (i3), int>::same check_i3;
sametype<decltype (i4), int>::same check_i4;
sametype<decltype (ci1), const int>::same check_ci1;
sametype<decltype (ir1), int&>::same check_ir1;
sametype<decltype (s1), std::string>::same check_s1;
sametype<decltype (s2), std::string>::same check_s2;
sametype<decltype (s3), std::string>::same check_s3;
прекрасно компилирует , поэтому я не ошибся!
decltype
других выражений
В противном случае, где expr
не определено в терминах поиска имени (не в одном из указанных выше случаев), например, выражение (expr)
, decltype
реализует отдельную функцию (нодизайнеры C ++ не стали бы тратить на это другие ключевые слова.)
decltype(expr)
даст тип выражения, украшенный его lxrvalueness (lvalue / xvalue / prvalue-ness):
- prvalue (чистое rvalue) типа
T
дает T
- xvalue типа
T
дает T&&
- lvalue типа
T
дает T&
Это обратное правило вызова функции: если f
- это функция с типом возврата
T&
, выражение f()
является lvalue T&&
, выражение f()
является xvalue - обнаженный тип (чистый тип объекта, без ссылки)
T
, выражение f()
является prvalue
, а также для приведений: для обнаженного типа (чистый тип объекта, без ссылки) T
(T&)expr
является lvalue (T&&)expr
является xvalue (T)expr
является prvalue
Reference-ness - это кодирование lxrvalueness в типы.decltype
выполняет эту кодировку для сохранения и передачи lxrvalueness вещей.
Это полезно, когда вы хотите создать псевдоним выражения: lxrvalueness выражения expr
, которое является вызовом функции (либо нормально * 1120)* или с синтаксисом оператора, таким как a @ b
), совпадает с lxrvalueness alias()
, объявленным как decltype(expr) alias();
. Это может использоваться для чистой пересылки в общем коде:
// decorated type of an expression
#define EXPR_DEC_TYPE(expr) decltype((expr))
int i;
int &ri = i;
int fi();
int &fri();
EXPR_DEC_TYPE(i) alias_i = i; // int &
EXPR_DEC_TYPE(ri) alias_ri = ri; // int &
EXPR_DEC_TYPE(fi()) alias_fi(); // int alias_fi()
EXPR_DEC_TYPE(fri()) alias_fri(); // int &alias_fri()
Обратите внимание, что EXPR_DEC_TYPE(foo())
по конструкции равен declexpr(foo())
(в большинстве случаев), но вычисления отличаются:
declexpr(foo(args))
делает поиск имени для foo
, делает разрешение перегрузки, находит объявление, возвращает точный объявленный тип возврата, конец истории
EXPR_DEC_TYPE(foo(args))
находит тип объявления и затем вычисляет
тип T
выражения, являющегося возвращаемым типом naked (без
ссылка)
lxrvalueness LXR выражения в соответствии со ссылкамизаявленный тип возврата: lvalue для справки, xvalue r-reference ...
, затем он украшает тип T
с помощью LXR , чтобы получить тип decT
:
decT
равно T
, если LXR = prvalue decT
равно T&&
, если LXR = xvalue decT
равно T&
, если LXR = lvalue
EXPR_DEC_TYPE
возвращает decT
, что совпадает с объявленным типом возврата.