c++ decltype关键字的用法

1. 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, 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主要应用场景是模板函数

decltype在实际的开发中主要用于模板函数中,函数的返回值依赖于模板参数类型的情况。如下authAndAccess函数的返回值类型依赖于Container的元素类型。

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

 authenticateUser();

 return c[i];
}

此处的返回值auto并非类型推导的意思,而是C++ 11中的函数返回类型后置的表达方式,表明函数的返回类型在参数列表之后。函数返回类型后置的优势在于我们可以用函数的参数来指定返回值。

在c++ 14中auto关键字可以独立用于对函数的返回值进行类型推导,而不必采用c++ 11中的返回返回类型后置的声明方式:

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

 authenticateUser();

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

但上述写法在实际应用针对具体case可能存在问题,比如如果operator[]返回T&,auto的推导机制会返回T,下面的就会编译失败:

std::deque<int> d;

...

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

因为根据auto的推导机制,authAndAccess返回的是右值,所以编译不通过。authAndAccess函数需要声明为如下方式才可以保证该示例编译通过。

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

 authenticateUser();

 return c[i];
}

decltype(auto)不仅仅可以用于函数,也可以用于变量,可以完美推导变量的类型。

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&

再回到authAndAccess函数

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

注意到Container是一个非const的左值引用,这意味着用户可以修改Container内元素的值,同时也意味不能传递右值引用给它。

另外右值容器一般是一个临时对象,会在函数调用结束后不久被销毁,所以当用户传入一个右值引用的时候,一般我们要把返回元素拷贝它的一个副本。如何能够在不重载authAndAccess函数的情况下使它同时支持左值和右值呢?答案是通用引用。

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

为了保证推导结果的正确性,需要在实现中增加完美转发(std::forward)功能。

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

 authenticateUser();

 return std::forward<Container>(c)[i];
} // c++ 14版本
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版本

3. decltype使用的极端case

decltype(auto) f1() { // decltype(x) is int, so f1 returns int
 int x = 0;
 ...
 return x;
}

decltype(auto) f2() { // decltype((x)) is int&, so f2 returns int&
 int x = 0;
 ...
 return (x);
}

返回了一个局部变量的引用。

4. 需要记住的:

1) decltype总是返回与变量或者表达式完全相同的类型;

2) 对于类型T的非名称的左值表达式,decltype总是返回T&;

以上就是c++ decltype关键字的用法的详细内容,更多关于c++ decltype关键字的资料请关注我们其它相关文章!

(0)

相关推荐

  • C++11关于auto关键字的使用示例

    一.概述 auto关键字在c++98中已经出现,在98中定义为具有自动存储器的局部变量, c++11中标准委员会重新定义了auto关键字,表示一个类型占位符,告诉编译器,auto声明变量的类型必须由编译器在编译时期推导 而得. 注意事项: 1.auto关键字类型推断发生在编译期,程序运行时不会造成效率降低 2.auto关键字定义时就需要初始化 3.auto仅仅是一个占位符,它并不是一个真正的类型, 因此sizeof(auto)是错误的 4.auto不能作为函数的参数 5.auto不能定义数组,如

  • C++ const关键字的实例用法

    C++中的const更像编译阶段的#define const int m = 10; int n = m; 变量是要占用内存的,即使被const修饰也不例外.m,n两个变量占用不同的内存,int n = m:表示将m的值赋给n. 在C语言中,编译器会先到m所在的内存取出一份数据,再将这份数据赋给n: 在C++中,编译器会直接将10赋给m,没有读取内存的过程,和int n = 10效果一样. 在C++中的常量更类似于#define命令,是一个值替换的过程,只不过#define是在预处理阶段替换,而

  • C++中volatile关键字及常见的误解总结

    前言 近期看到C++标准中对volatile关键字的定义,发现和java的volatile关键字完全不一样,C++的volatile对并发编程基本没有帮助.网上也看到很多关于volatile的误解,于是决定写这篇文章详细解释一下volatile的作用到底是什么. 为什么用volatile? C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量,通常用于建立语言级别的 memory barrier.这是 BS 在 "The C++ Programming Language&

  • C++ decltype类型说明符

    1 基本语法 decltype 类型说明符生成指定表达式的类型.在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值. 语法为: decltype( expression ) 编译器使用下列规则来确定expression 参数的类型. 如果 expression 参数是标识符或类成员访问,则 decltype(expression) 是 expression 命名的实体的类型.如果不存在此类实体或 expression 参数命名一组重载函数,则编译器将生成错误消息. 如果 expr

  • C++11新特性中auto 和 decltype 区别和联系

    C++11新特性中auto 和 decltype 区别和联系 一. auto简介 编程时候常常需要把表达式的值付给变量,需要在声明变量的时候清楚的知道变量是什么类型.然而做到这一点并非那么容易(特别是模板中),有时候根本做不到.为了解决这个问题,C++11新标准就引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型.和原来那些只对应某种特定的类型说明符(例如 int)不同.auto 让编译器通过初始值来进行类型推演.从而获得定义变量的类型,所以说 auto 定义的变量必须有初始

  • C/C++ 中const关键字的用法小结

    C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性. Const作用 NO. 作用 说明 参考 1 可以定义const常量 const int Max = 100; 2 便于进行类型检查 const常量有数据类型,而宏常量没有数据类型.编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误 void f(const int i) { ---} //对传入的参数进行类型检查,不匹配进行提示 3 可以保护被修

  • 详解c++中的 static 关键字及作用

    注:若没有特指是 静态成员时,默认都是普通成员: 1 类中的普通成员 类中的成员变量 和 成员函数 是分开存储的.其中, 1)每个对象都有独立的成员变量:成员变量可以存储在 栈空间.堆空间.全局数据区: 2)所有对象共享类的成员函数:成员函数 只能存储在 代码段: 2 类中的静态成员(static) 类中的静态成员 1.用 static关键字 修饰: 2.可以用 类名::成员名 访问 静态成员: 3.静态成员 属于 整个类: 4.静态成员 是所属类的成员,其它类不能访问: 5.静态成员的内存分配

  • C++ override关键字使用详解

    C++ override从字面意思上,是覆盖的意思,实际上在C++中它是覆盖了一个方法并且对其重写,从而达到不同的作用.在我们C++编程过程中,最熟悉的就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法.还有一个典型应用就是在继承中也可能会在子类覆盖父类的方法. 公有继承包含两部分:一是"接口"(interface),二是 "实现" (implementation). 例如Person类的几种成员函数的继承方式: c

  • c++使用正则表达式提取关键字的方法

    下面看下c++通过正则表达式提取关键字,代码如下所示: string text = "岳云鹏的对象叫铁锤"; regex pattern("(.*)的对象叫(.*)"); smatch results; if (regex_match(text, results, pattern)) { for (auto it = results.begin(); it != results.end(); ++it) cout << *it << endl

  • C++11特性小结之decltype、类内初始化、列表初始化返回值

    作用:返回表达式或变量的类型 返回值规则: 若e是一个左值(lvalue,即"可寻址值"),则decltype(e)将返回T& 若e是一个临终值(xvalue),则返回值为T&& 若e是一个纯右值(prvalue),则返回值为T decltype()不会执行括号内的表达式,decltype返回的类型是用于声明的,不能用于单纯的判断.比如decltype(a)==int,是不可以的,只能是在定义新的变量.返回值的地方使用: int a=1; decltype(a)

  • C++中volatile关键字的使用详解以及常见的误解

    为什么使用volatile ? C/C++中的 volatile 关键字 和const对应,用来修饰变量,通常用于建立语言级别的memory barrier.这是BS在"The C++ Programming Language"对volatile修饰词的解释: A volatile specifier is a hint to a compiler that an object may change its value in ways not specified by the lang

随机推荐