[dcl.type.decltype]

# 9 Declarations [[dcl]](./#dcl)

## 9.2 Specifiers [[dcl.spec]](dcl.spec#dcl.type.decltype)

### 9.2.9 Type specifiers [[dcl.type]](dcl.type#decltype)

#### 9.2.9.6 Decltype specifiers [dcl.type.decltype]

[decltype-specifier:](#nt:decltype-specifier "9.2.9.6 Decltype specifiers [dcl.type.decltype]")  
decltype ( [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") )

[1](#1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1699)

For an expression E, the type denoted by decltype(E) is defined as follows:

- [(1.1)](#1.1)

  if E is an unparenthesized [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") naming a structured binding ([[dcl.struct.bind]](dcl.struct.bind "9.7 Structured binding declarations")),decltype(E) is the referenced type as given in
the specification of the structured binding declaration;

- [(1.2)](#1.2)

  otherwise, if E is an unparenthesized [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") naming a constant template parameter ([[temp.param]](temp.param "13.2 Template parameters")),decltype(E) is the type of the template parameter
after performing any necessary
type deduction ([[dcl.spec.auto]](dcl.spec.auto "9.2.9.7 Placeholder type specifiers"), [[dcl.type.class.deduct]](dcl.type.class.deduct "9.2.9.8 Deduced class template specialization types"));

- [(1.3)](#1.3)

  otherwise, if E is an unparenthesized [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") or
an unparenthesized
class
member access ([[expr.ref]](expr.ref "7.6.1.5 Class member access")), decltype(E) is the
type of the entity named by E[.](#1.3.sentence-1)
  If there is no such entity, the program is ill-formed;

- [(1.4)](#1.4)

  otherwise, if E is an unparenthesized [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]"),decltype(E) is the type of the entity, object, or value
designated by the [*splice-specifier*](basic.splice#nt:splice-specifier "6.6 Splice specifiers [basic.splice]") of E;

- [(1.5)](#1.5)

  otherwise, if E is
an xvalue, decltype(E) is T&&, where T is the type
of E;

- [(1.6)](#1.6)

  otherwise, if E is an lvalue, decltype(E) is T&, where T is the type of E;

- [(1.7)](#1.7)

  otherwise, decltype(E) is the type of E[.](#1.7.sentence-1)

The operand of the decltype specifier is an [unevaluated operand](expr.context#def:unevaluated_operand "7.2.3 Context dependence [expr.context]")[.](#1.sentence-2)

[*Example [1](#example-1)*: const int&& foo();int i;struct A { double x; };const A* a = new A();decltype(foo()) x1 = 17; // type is const int&&decltype(i) x2; // type is intdecltype(a->x) x3; // type is doubledecltype((a->x)) x4 = x3; // type is const double&decltype([:^^x1:]) x5 = 18; // type is const int&&decltype(([:^^x1:])) x6 = 19; // type is const int&void f() {[](auto ...pack) {decltype(pack...[0]) x7; // type is intdecltype((pack...[0])) x8; // type is int&}(0);} â *end example*]

[*Note [1](#note-1)*:

The rules for determining types involving decltype(auto) are specified
in [[dcl.spec.auto]](dcl.spec.auto "9.2.9.7 Placeholder type specifiers")[.](#1.sentence-3)

â *end note*]

[2](#2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L1763)

If the operand of a [*decltype-specifier*](#nt:decltype-specifier "9.2.9.6 Decltype specifiers [dcl.type.decltype]") is a prvalue
and is not a (possibly parenthesized) immediate invocation ([[expr.const]](expr.const "7.7 Constant expressions")),
the temporary materialization conversion is not applied ([[conv.rval]](conv.rval "7.3.5 Temporary materialization conversion"))
and no result object is provided for the prvalue[.](#2.sentence-1)

The type of the prvalue may be incomplete or an abstract class type[.](#2.sentence-2)

[*Note [2](#note-2)*:

As a result, storage is not allocated for the prvalue and it is not destroyed[.](#2.sentence-3)

Thus, a class type is not instantiated
as a result of being the type of a function call in this context[.](#2.sentence-4)

In this context, the common purpose of
writing the expression is merely to refer to its type[.](#2.sentence-5)

In that sense, a[*decltype-specifier*](#nt:decltype-specifier "9.2.9.6 Decltype specifiers [dcl.type.decltype]") is analogous to a use of a [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]"),
so the usual reasons for requiring a complete type do not apply[.](#2.sentence-6)

In particular,
it is not necessary to allocate storage for a temporary object or to enforce the
semantic constraints associated with invoking the type's destructor[.](#2.sentence-7)

â *end note*]

[*Note [3](#note-3)*:

Unlike the preceding rule, parentheses have no special meaning in this context[.](#2.sentence-8)

â *end note*]

[*Example [2](#example-2)*: template<class T> struct A { ~A() = delete; };template<class T> auto h()-> A<T>;template<class T> auto i(T) // identity-> T;template<class T> auto f(T) // #1-> decltype(i(h<T>())); // forces completion of A<T> and implicitly uses A<T>​::​~A()// for the temporary introduced by the use of h().// (A temporary is not introduced as a result of the use of i().)template<class T> auto f(T) // #2-> void;auto g() -> void { f(42); // OK, calls #2. (#1 is not a viable candidate: type deduction// fails ([[temp.deduct]](temp.deduct "13.10.3 Template argument deduction")) because A<int>​::​~A() is implicitly used in its// [*decltype-specifier*](#nt:decltype-specifier "9.2.9.6 Decltype specifiers [dcl.type.decltype]"))}template<class T> auto q(T)-> decltype((h<T>())); // does not force completion of A<T>; A<T>​::​~A() is not implicitly// used within the context of this [*decltype-specifier*](#nt:decltype-specifier "9.2.9.6 Decltype specifiers [dcl.type.decltype]")void r() { q(42); // error: deduction against q succeeds, so overload resolution selects// the specialization âq(T) -> decltype((h<T>()))'' with T=int;// the return type is A<int>, so a temporary is introduced and its// destructor is used, so the program is ill-formed} â *end example*]
