Use of the c++ decltype keyword

  • 2020-11-25 07:24:21
  • OfStack

1. What is the purpose of the decltype keyword

Given the name or expression of a variable, decltype returns the type of the variable or expression. As shown below:


const int i = 0; // decltype(i) is const int

bool f(const Widget& w); // decltype(w) is const Widget& . decltype(f) is bool(const Widget&)

struct Point {

int x, y; // decltype(Point::x) is int, decltype(Point::y) is int

};

Widget w; // decltype(w) is Widget

if (f(w)) ... // decltype(f(w)) is bool

template<typename T>class vector {

public:

...

T& operator[](std::size_t index);...

};

vector<int> v; // decltype(v) is vector<int>

if (v[0] == 0) ... // decltype(v[0]) is int&

2.decltype is mainly used for template functions

decltype was primarily used in actual development in template functions, where the return value of the function depends on the template parameter type. The return value type of the following authAndAccess function depends on the element type of Container.


template<typename Container, typename Index>
auto authAndAccess(Container& c, Index i) -> decltype(c[i]) {

 authenticateUser();

 return c[i];
}

The return value auto here is not meant as a type derivation, but rather as a postposition representation of the function return type in C++ 11, indicating that the function return type follows the argument list. The advantage of a function return type postposition is that we can specify the return value with the function's arguments.

In c++ 14, the auto keyword can be used to type derive the return value of a function independently, instead of declaring the return type postset as in c++ 11:


template<typename Container, typename Index>
auto authAndAccess(Container& c, Index i) {

 authenticateUser();

 return c[i]; // return type deduced from c[i]
}

However, the above method may have problems in practical application for specific case, such as if operator[] returns T & The derivation mechanism of auto returns T, and the following one will fail to compile:


std::deque<int> d;

...

authAndAccess(d, 5) = 10; //return d[5], then assign 10 to it; this won't compile!

Because authAndAccess returns an rvalue according to the derivation mechanism of auto, the compilation does not pass. The authAndAccess function needs to be declared as follows in order for the example to compile.


template<typename Container, typename Index>
decltype(auto) authAndAccess(Container& c, Index i){

 authenticateUser();

 return c[i];
}

decltype(auto) can be used not only for functions, but also for variables, and can be a perfect derivation of the type of a variable.


Widget w;
const Widget& cw = w;
auto myWidget1 = cw; // auto type deduction: myWidget1's type is Widget

decltype(auto) myWidget2 = cw; // decltype type deduction: myWidget2's type is const Widget&

Let's go back to the authAndAccess function


template<typename Container, typename Index>
decltype(auto) authAndAccess(Container& c, Index i);

Note that Container is an l_value reference for a non-const, which means that the user can modify the value of an element within Container, but also means that an r_value reference cannot be passed to it.

In addition, rvalue container 1 is usually a temporary object that will be destroyed shortly after the end of the function call, so when a user passes in an rvalue reference, we usually make a copy of the returned element. How can you make the authAndAccess function support both left and right values without overloading it? The answer is a generic quote.


template<typename Container, typename Index>
decltype(auto) authAndAccess(Container&& c,Index i);

In order to ensure the correctness of the derivation results, the function of perfect forwarding (std::forward) should be added into the implementation.


template<typename Container, typename Index>
decltype(auto)authAndAccess(Container&& c, Index i){

 authenticateUser();

 return std::forward<Container>(c)[i];
} // c++ 14 version 

template<typename Container, typename Index>
auto authAndAccess(Container&& c, Index i)
-> decltype(std::forward<Container>(c)[i])
{
 authenticateUser();

 return std::forward<Container>(c)[i];
} // c++ 11 version 

3. Extreme case used by decltype


template<typename Container, typename Index>
auto authAndAccess(Container& c, Index i) -> decltype(c[i]) {

 authenticateUser();

 return c[i];
}
0

Returns a reference to a local variable.

4. Things to remember:

1) decltype always returns the exact same type as the variable or expression;

2) decltype always returns T for a non-named lvalue expression of type T & ;

The above is c++ decltype keyword usage details, more information about c++ decltype keyword please pay attention to other related articles on this site!


Related articles: