---
tags: CSE
---
```cpp
decltype(expr);
```
based on <span style="color:red">__expr__</span>, the type deduction rule goes differently.
## Case 1: <span style="color:red">__expr__</span> is an unparenthesized id-expression or an unparenthesized class member access expression
in this case, ```decltype``` yields the type of the entity named by this expression.
- unparenthesized id-expression example:
```cpp=
const int i = 0; // decltype(i) -> const int
bool f(const Obj& o); // decltype(f) -> bool (const Obj&)
// decltype(o) -> const Obj&
```
- unparenthesized class member access expression example:
```cpp=
class points // decltype(points::x) -> int
{ // decltype(points::y) -> int
int x, y;
}p; // decltype(p.x) -> int
// decltype(p.y) -> int
points *pp = &p; // decltype(pp->x) -> int
// decltype(pp->y) -> int
// decltype((*pp).x) -> int
// decltype((*pp).y) -> int
// but decltype(*pp) yields point&
// we'll talk about it later
template<typename T>
class vector
{
public:
T& operator[](size_t i);
};
vector<int> v;
v[0]; // decltype(v[0]) -> int&
```
## Case 2: <span style="color:red">__expr__</span> is any other expression of type T
in the case, ```decltype``` works like:
1. if <span style="color:red">__expr__</span> is lvalue, it yields T&
2. if <span style="color:red">__expr__</span> is xvalue, it yields T&&
3. if <span style="color:red">__expr__</span> is prvalue, it yields T
- lvalue example:
```cpp=
int x, *px = &x, arr[] = {0,1,2};
decltype((x)) a = x; // decltype((x)) -> int&
decltype(*px) b = x; // decltype(*px) -> int&
decltype(arr[0]) c = x; // decltype(arr[0]) -> int&
// u may wonder what's the difference between this and the previous class operator[]
// here's the different:
template<typename T>
class vector
{
public:
// notice it doesn't return reference
T operator[](size_t i);
};
vector<int> v;
decltype(v[0]) d; // decltype(v[0]) -> int, not int&.
// it changes with the return type
```
- xvalue example:
```cpp=
int&& f();
int x;
decltype(std::move(x)) a = 0; // decltype(std::move(x)) -> int&&
decltype(f()) b = 0; // decltype(f()) -> int&&
decltype((int[3]){0,1,2}[0]) c = 0;
// decltype((int[3]){0,1,2}[0]) -> int&&
```
- prvalue example:
```cpp=
int f();
int x, y;
decltype(f()) a = 0; // decltype(f()) -> int
decltype(x+y) b = 0; // decltype(x+y) -> int
```
## ```decltype(auto)```
in c++14, the syntax is introduced.
just like ```auto```, it deduces a type from its initializer, but it performs the type deduction using the decltype rules.
```cpp=
decltype(auto) a = 1; // type is int
decltype(auto) b = (1); // type is int
decltype(auto) c = a; // type is int
decltype(auto) d = (a); // type is int&
decltype(auto) e = a + b; // type is int
string source = "0123";
decltype(auto) s = move(source); // type is string&&
string&& rs = "1234";
decltype(auto) s = (rs); // type is string&
```
this syntax is used more often in function return type, for example:
```cpp=
// c++ 14 required
template<typename Container, typename Idx>
decltype(auto) authAndAccess(Container&& c, Idx i)
{
AuthUser();
return std::forward<Container>(c)[i];
}
```
one more thing to mention, ```decltype(auto)``` in function return type acts like declaration one.
```cpp=
decltype(auto) f1()
{
int x = 0;
// decltype(x) is int, so f1 returns int
return x;
}
decltype(auto) f2()
{
int x = 0;
// decltype((x)) is int&, so f2 returns int&
return (x);
}
```
---
reference:
- Effective Modern C++ 1/e, Scott Meyers
- https://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues
- https://hackmd.io/@Mes/Cpp_Miner/https%3A%2F%2Fhackmd.io%2F%40Mes%2FMiner_MoveSemantics
- https://en.cppreference.com/w/cpp/language/decltype
- https://stackoverflow.com/questions/21369113/what-is-the-difference-between-auto-and-decltypeauto-when-returning-from-a-fun
- https://stackoverflow.com/questions/24109737/what-are-some-uses-of-decltypeauto
- https://www.quora.com/What-is-a-array-rvalue-in-C++