【C++0x】表达式之类型(decltype)
语法形式:decltype (expression)
其中,这里的括号必不可少(这点不同于sizeof操作符)。decltype(e)可看到是一个类型别名,并且不会对表达式e进行计算(即只有编译时行为而无运行时行为)。另外,不允许把decltype作用于一个类型,因为没有任何理由要这样做。
确定decltype(e)类型的规则如下:
Rule-1. 如果e是一个标识符表达式或者类成员访问表达式,那么decltype(e)就是e所命名的实体的类型。如果没有此实体或者e命名了一个重载函数集,那么程序是ill-formed的。
Rule-2. 如果e是一个函数调用或者一个重载操作符调用(忽略e外面的括号),那么decltype(e)就是该函数的返回类型。
Rule-3. 否则,假设e的类型是T:如果e是一个左值,则decltype(e)就是T&;否则(e是一个右值),decltype(e)就是T。
举例分析如下(内容来自参考Ref1):
eg1 名字空间或局部作用域内的变量(Rule-1)
int a;
int& b = a;
const int& c = a;
const int d = 5;
const A e;
(注:不能直接编译,这里写出来只是分析)
decltype(a) // int
decltype(b) // int&
decltype(c) // const int&
decltype(d) // const int
decltype(e) // const A
但需要注意括号可能会影响结果,例如:
decltype((a)); // int& (此时(a)表达式不满足Rule-1和Rule-2,应用Rule-3,而表达式(a)是一个左值,所以为int&)
eg2 函数形参(Rule-1)
void foo(int a, int& b, float&& c, int* d)
{
decltype(a) // int
decltype(b) // int&
decltype(c) // float&&
decltype(d) // int*
}
eg3 函数类型(Rule-1)
int foo(char);
int bar(char);
int bar(int);
decltype(foo) // int(char)
decltype(bar) // error, bar is overloaded
但需要注意当形成函数指针时适用Rule-3:
decltype(&foo) // int(*)(char)
decltype(*&foo) // int(&)(char)
eg4 数据类型(Rule-1)
int a[10];
decltype(a) // int[10]
eg5 成员变量(Rule-1)
class A {
int a;
int& b;
static int c;
void foo() {
decltype(a) // int
decltype(this->a) // int
decltype((*this).a) // int
decltype(b) // int&
decltype(c) // int (static members are treated as variables in namespace scope)
}
void bar() const {
decltype(a) // int
decltype(b) // int&
decltype(c) // int
}
};
A aa;
const A& caa = aa;
decltype(aa.a) // int
decltype(aa.b) // int&
decltype(caa.a) // int
但内置操作符.*和->*适用Rule-3:
decltype(aa.*&A::a) // int&
decltype(aa.*&A::b) // illegal, cannot take the address of a reference member
decltype(caa.*&A::a) // const int&
eg6 this(Rule-3)
class X {
void foo() {
decltype(this) // X*,因为this是右值
decltype(*this) // X&,因为*this是左值
}
void bar() const {
decltype(this) // const X*
decltype(*this) // const X&
}
};
eg7 指向成员变量和成员函数的指针(Rule-1)
class A {
int x;
int& y;
int foo(char);
int& bar() const;
};
decltype(&A::x) // int A::*
decltype(&A::y) // error: pointers to reference members are disallowed (8.3.3 (3))
decltype(&A::foo) // int (A::*) (char)
decltype(&A::bar) // int& (A::*) () const
eg8 字面值(Rule-3)
(字符串字面值是左值,其它字面值都是右值)
decltype("decltype") // const char(&)[9]
decltype(1) // int
eg9 冗余的引用符(&)和CV修饰符
由于decltype表达式是一个类型别名,因此冗余的引用符(&)和CV修饰符被忽略:
int& i = ...;
const int j = ...;
decltype(i)& // int&. The redundant & is ok
const decltype(j) // const int. The redundant const is ok
eg10 函数调用(Rule-2)
int foo();
decltype(foo()) // int
float& bar(int);
decltype (bar(1)) // float&
class A { ... };
const A bar();
decltype (bar()) // const A
const A& bar2();
decltype (bar2()) // const A&
eg11 内置操作符(Rule-3)
decltype(1+2) // int (+ returns an rvalue)
int* p;
decltype(*p) // int& (* returns an lvalue)
int a[10];
decltype(a[3]); // int& ([] returns an lvalue)
int i; int& j = i;
decltype (i = 5) // int&, because assignment to int returns an lvalue
decltype (j = 5) // int&, because assignment to int returns an lvalue
decltype (++i); // int&
decltype (i++); // int (rvalue)
如何用程序验证decltype的结果?可以参考下面的程序对上面的分析结果进行验证:
F:\tmp>type decltype_eg1.cpp
#include <iostream>
#include <string>
using namespace std;
template <typename T>
string Foo()
{
return "unknown";
}
template <>
string Foo<int>()
{
return "int";
}
template <>
string Foo<const int>()
{
return "const int";
}
template <>
string Foo<int &>()
{
return "int&";
}
template <>
string Foo<const int&>()
{
return "const int&";
}
class A{};
template <>
string Foo<A>()
{
return "A";
}
int main()
{
int a;
int &b = a;
const int &c = a;
const int d = 5;
A e;
double f;
cout << "a: " << Foo<decltype(a)>() << endl;
cout << "b: " << Foo<decltype(b)>() << endl;
cout << "c: " << Foo<decltype(c)>() << endl;
cout << "d: " << Foo<decltype(d)>() << endl;
cout << "e: " << Foo<decltype(e)>() << endl;
cout << "f: " << Foo<decltype(f)>() << endl;
}
F:\tmp>g++ decltype_eg1.cpp -std=c++0x
F:\tmp>a.exe
a: int
b: int&
c: const int&
d: const int
e: A
f: unknown
F:\tmp>gcc --version
gcc (GCC) 4.3.0 20080305 (alpha-testing) mingw-20080502
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
【C++0x】表达式之类型(decltype)的更多相关文章
- LINQ to Entities 不支持 LINQ 表达式节点类型“ArrayIndex”
我就不屁话,能一张图就解决的就不说话了 2015-03-28 14:53:24,440 [10] ERROR log - System.NotSupportedException: LINQ to E ...
- LINQ to Entities 不支持 LINQ 表达式节点类型“Invoke”(笔记)
今天使用使用动态查询的时候出现出现错误“LINQ to Entities 不支持 LINQ 表达式节点类型‘Invoke’.”,代码如下: IQueryable<CUSTOMER> que ...
- 无法确定条件表达式的类型,因为“<null>”和“System.DateTime”之间没有隐式转换----解决办法
例子:(报错了) public DateTime? time { get; set; } time = item.HospOutDate.HasValue ? DateTime.Parse(item. ...
- 深入学习C#匿名函数、委托、Lambda表达式、表达式树类型——Expression tree types
匿名函数 匿名函数(Anonymous Function)是表示“内联”方法定义的表达式.匿名函数本身及其内部没有值或者类型,但是可以转换为兼容的委托或者表达式树类型(了解详情).匿名函数转换的计算取 ...
- 无法将 lambda 表达式 转换为类型“System.Delegate”,因为它不是委托类型
今天写winform的时候遇到一个问题,提示: 无法将 lambda 表达式 转换为类型“System.Delegate”,因为它不是委托类型, 主要是为了在子线程中更新UI线程,在wpf中同样的写法 ...
- 工作总结 无法确定条件表达式的类型,因为“<null>”和“System.DateTime”之间没有隐式转换 解决办法 object——Nullable<T> (可空类型)
可空值类型 备注 一种类型认为是可以为 null,如果它可以分配一个值,也可以分配null,这意味着类型具有无论如何没有值. 默认情况下,所有都引用类型,如String,是否可以为 null, ...
- java 运算符使表达式结果类型自动提升
1.表达式中的自动类型提升: 表达式求值时,Java自动的隐含的将每个byte.short或char操作数提升为int类型,这些类型的包装类型也是可以的. 例如:short s1 = 1; s1 = ...
- 无法将 lambda 表达式 转换为类型“System.Delegate”,因为它不是委托类型
this.BeginInvoke(() => { this.btnQuery.Enabled = false; //禁用查询 }); 跨线程调用时,编译上面的代码将提示 对于Control.In ...
- Entity Framework解决sql 条件拼接,完美解决 解决 不支持 LINQ 表达式节点类型“Invoke”【转】
传统的操作数据库方式,筛选数据需要用StringBuilder拼接一大堆的WHERE子句. 在Entity Framework中,代码稍有不慎就会造成巨大性能消耗,如: using(var db=ne ...
随机推荐
- 关于vue2用vue-cli搭建环境后域名代理的http-proxy-middleware解决api接口跨域问题
在vue中用http-proxy-middleware来进行接口代理,比如:本地运行环境为http://localhost:8080但真实访问的api为 http://www.baidu.com这时我 ...
- Android 原生 MediaPlayer 和 MediaCodec 的区别和联系(二)
目录: (3)Android 官方网站 对 MediaPlayer的介绍 正文: Android 官方网站 对 MediaPlayer的介绍 MediaPlayer pub ...
- linux 软件包 rpm命令之安装、更新、卸载、依赖
软件包分类1.源码包2.二进制包二进制包是源码包编译后产生的文件..exe文件是适用于windows平台的二进制包:RPM包适用于redhat系列的二进制包:deb包是适用于ubuntu平台的二进制包 ...
- ubuntu 命令、linux环境变量设置
解压与压缩: tar.gz格式tar -xzvf xxx jar格式jar -xvf xxx.jar zip格式unzip xxx.zip zip -r xxx.zip xxx unarunar -e ...
- oracle 导入导出 dmp 的三种方式
1.命令行参数 比如:exp scott/tiger@orcl tables=emp file=D:\test.dmp 2.交互提示符 比如:C:\Users\Administrator>exp ...
- 64位win10系统中无法开启vmware的VT-X嵌套虚拟化功能的解决方法
在升级了win10操作系统之后,发现Vmware Workstation在安装64位操作系统虚拟机的或者要使用Intel VT-X/EPT的时候,会一直弹出vt-x被禁用的提示,如下图: ...
- PHP匹配当前传入是何种类型
本文出至:新太潮流网络博客 /** * [is_string_regular_type 正则自动验证传入数据] * @E-mial wuliqiang_aa@163.com * @TIME 2017- ...
- “拒绝了对对象数据库的 EXECUTE 权限”之解决
“拒绝了对对象'aspnet_CheckSchemaVersion'的 EXECUTE 权限”之解决 [错误状态] “/XXX”应用程序中的服务器错误. ----------------------- ...
- MongoDB 安装和使用问题总结
1. 一直安装不了[一直next下去但最后没有发现生成文件夹] 去掉 Installing MongoDB Compass 前面的打勾 2. 需要开两个cmd运行mongodb 开第一个,输入以下运行 ...
- 关于jquery的serialize方法转换空格为+号的解决方法
jquery的 serialize()方法,可以对表单项进行序列化,这本来是很方便的一个功能:但是实际使用中去发现了如下问题:例如:< textarea name="content&q ...