--- 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++