Item 3 Understand decltype

引子

decltype可以用来获取表达式类型,且通常就是我们想要的类型。

正文

首先,从最基本的情况开始,decltype返回准确类型:

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
};
Widget w;     //decltype(w) is Widget
if(f(w))...       //decltype(f(w)) is bool

template
class vector{
public:
...
T& operator[](std::size_t index); 
};
vector v;  //decltype(v) is vector
...
if(v[0] == 0)      //decltype(v[0]) is int&

在C++11中,decltype最基本的应用是声明返回值类型依赖参数类型的模板函数。

template
auto authAndAccess(Container& c, Index i)
-> decltype(c[i])
{
  ...
  return c[i];
}

C++11允许对独立声明的lambda表达式返回类型进行推导,C++14扩展到支持推导所有lambda表达式和函数类型,包含多次声明的情况。

template
auto authAndAccess(Container& c, Index i)
{
  ...
  return c[i];
}

此处auto的使用会发生类型推导。编译器会根据函数实现推导返回值类型。

此处的auto与推导类型无关,返回值类型完全依赖于c和i。
根据Item 2的介绍,我们了解到auto作为函数返回值类型时,会自动推导返回值类型;而对于大多数容器,operator[]返回T&类型的对象。但根据Item 1我们又知道,模板类型推导过程中,引用特性会被忽略,因此:

std::deque d;
...
authAndAccess(d, 5) = 10;

上述代码中,d[5]返回int&,但是auto类型推导忽略了引用,因此返回值类型是int,再用10对int赋值就无法编译了。
此时可以请decltype出马,推导返回值的准确类型啦!

template
decltype(auto)
authAndAccess(Container& c, Index i)
{
   ...
   return c[i];
}

此时,返回值类型为T&。除了函数返回值类型,decltype(auto)也可以用于初始化表达式变量类型的声明:

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

接下来,我们继续修改函数,使它不仅可以接受左值参数,还可以接受右值参数。形式如下:

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

在使用通用引用时,要同时使用std::forward,传递参数的特性。
最终,C++11和C++14的写法如下:

template
auto
authAndAccess(Container&& c, Index i)
-> decltype(std::forward(c)[i])
{
  ...
  return std::forward(c)[i];
}

template
decltype(auto)
authAndAccess(Container&& c, Index i)
{
  ...
  return std::forward(c)[i];
}

将decltype应用于变量名,会产生该变量名的声明类型。变量名是左值,但它不影响decltype的行为。但是对左值表达式,情况就复杂了,使用decltype会产生左值引用。

int x = 0;
decltype(x); //type is int
decltype((x)); //type is int&

总结

  • decltype总是能获取到变量或表达式的真实类型
  • 对于类型为T的左值表达式,decltype总会返回类型T&
  • C++14支持decltype(auto)

你可能感兴趣的:(Item 3 Understand decltype)