c++11-17 模板核心知识(九)—— 理解decltype与decltype(auto)
与模板参数推导和auto推导一样,decltype的结果大多数情况下是正常的,但是也有少部分情况是反直觉的。
decltype介绍
给定一个name或者expression,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 }; // decltype(Point::y) is int Widget w; // decltype(w) is Widget if (f(w)) … // decltype(f(w)) is bool template<typename T> // simplified version of std::vector 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&
很直观,没有例外情况。 注意:decltype与auto不同,不会消除const和引用。
为什么需要decltype
比如我们需要声明一个函数模板,函数的返回值类型依赖函数参数的类型。在C++11中,常见的例子是返回一个container对应索引的值:
template <typename Container, typename Index> // works, but requires refinement auto authAndAccess(Container &c, Index i) -> decltype(c[i]) { return c[i]; }
注意:这里的auto跟类型推导没有任何关系,它只是表明了这里使用了C++11的
trailing return type.
decltype(auto)
在C11中只允许单语句的lambda表达式被推导,在C14中之中行为被拓展到所有lambda和所有函数,包括多语句。在C++14中,上述代码我们可以简写为:
template<typename Container, typename Index> // C++14; not quite correct auto authAndAccess(Container& c, Index i) { return c[i]; // return type deduced from c[i] }
注意:这里的auto就跟类型推导有关系了。 在前面讲auto推导规则的文章中提到过,auto作用在函数返回值时,使用的是模板参数推导规则,这里就会出现问题:operator []
我们希望它返回引用,但是使用auto使用模板参数推导规则时,引用会被忽略,所以下面的代码会报错:
template <typename Container, typename Index> auto authAndAccess(Container &c, Index i) { return c[i]; } std::vector<int> v{1,2,3,4,5}; authAndAccess(v,2) = 10; // error: expression is not assignable
但是使用
auto -> decltype()则不会报错,因为这里auto不代表参数参数推导:
template <typename Container, typename Index> auto authAndAccess(Container &c, Index i) -> decltype(c[i]) { return c[i]; } std::vector<int> v{1,2,3,4,5}; authAndAccess(v,2) = 10;
所以,要想让authAndAccess在使用auto的情况下返回引用,在C++14中,我们可以使用decltype(auto):
template <typename Container, typename Index> decltype(auto) authAndAccess(Container &c, Index i) { return c[i]; } std::vector<int> v{1,2,3,4,5}; authAndAccess(v,2) = 10;
decltype(auto)中的auto代表返回值需要被自动推导,decltype代表使用decltype来推导返回值类型。
decltype(auto)不仅可以声明函数返回值,还可以声明变量:
Widget w; const Widget& cw = w; // auto type deduction : myWidget1's type is Widget decltype(auto) myWidget2 = cw; // decltype type deduction : myWidget2's type is const Widget&
注意(entity)
decltype的规则可以看官网:decltype specifier,概况下可以分为两大类:
decltype ( entity )
: 如果entity是一个不被括号包围的标识符、类访问表达式,那么decltype ( entity )
与entity类型一致。decltype ( expression )
: 如果expression是一个表达式,计算结果为类型T,那么: 如果expression为xvalue,那么decltype的结果是T&&.- 如果expression为lvalue,那么decltype的结果是T&.
- 如果expression为prvalue,那么decltype的结果是T.
注意第一点中强调了entity是一个不被括号包围的标识符。因为当一个标识符被括号包围时,它就是一个左值表达式了,对应上面第二大点的第二小点。比如说
int x = 0;,x是一个标识符,所以
decltype(x)的结果为int。但是(x)就是一个左值表达式,
decltype((x))的结果就是int&。所以下面的用法是不同的:
decltype(auto) f1() { int x = 0; … return x; // decltype(x) is int, so f1 returns int } decltype(auto) f2() { int x = 0; … return (x); // decltype((x)) is int&, so f2 returns int& }
官网的例子能很好的概况decltype最常见的用法:
#include <iostream> struct A { double x; }; const A* a; decltype(a->x) y; // type of y is double (declared type) decltype((a->x)) z = y; // type of z is const double& (lvalue expression) template<typename T, typename U> auto add(T t, U u) -> decltype(t + u) // return type depends on template parameters // return type can be deduced since C++14 { return t + u; } int main() { int i = 33; decltype(i) j = i * 2; std::cout << "i = " << i << ", " << "j = " << j << '\n'; auto f = [](int a, int b) -> int { return a * b; }; decltype(f) g = f; // the type of a lambda function is unique and unnamed i = f(2, 2); j = g(3, 3); std::cout << "i = " << i << ", " << "j = " << j << '\n'; }
(完)
朋友们可以关注下我的公众号,获得最及时的更新:
- c++11-17 模板核心知识(六)—— 理解auto推导规则
- c++11-17 模板核心知识(三)—— 非类型模板参数 Nontype Template Parameters
- c++11-17 模板核心知识(十)—— 区分万能引用(universal references)和右值引用
- C++11 理解 (一) 之 auto与decltype的运用
- C++11系列-改进的类型推导:auto、decltype和新的函数语法
- 跳槽面试必备:深入理解 Java 多线程核心知识
- C++11 auto 和decltype
- elasticsearch核心知识--43.关于内核知识doc_value的理解
- C++11 auto&decltype
- elasticsearch核心知识--26.一致性原理以及quorum机制理解
- 网络核心知识理解
- C++11系列-改进的类型推导:auto、decltype和新的函数语法
- 深入理解 Java 多线程核心知识:跳槽面试必备
- C++11新特性——auto和decltype类型推导
- C++11 条款1:理解模板类型推导
- C++11特性--auto,decltype,返回类型后置,using=,nullptr
- C++11 理解 (十七) 之 变长参数模板
- 杂货边角(12):C++11动态性来源之类型推断 && auto\decltype\追踪返回类型
- const关键字核心相关知识及decltype类型指示符
- 【C++11新特性】模板优化和关键字:nullptr、std::nullptr_t、auto