转载自http://www.cppblog.com/flyinghare/archive/2011/06/23/149225.html
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.
参考资料:
Ref1: Decltype
(revision 6): proposed wording
Ref2: Decltype (revision 7): proposed wording