天天看點

【C++0x】表達式之類型(decltype)

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(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& b;

    static int

c;

    void foo()

decltype(a)          //

decltype(this->a)    //

        decltype((*this).a)  //

decltype(b)          //

decltype(c)          // int (static

members are treated as variables in namespace scope)

    void bar() const

        decltype(a)   //

        decltype(b)   //

        decltype(c)  

// int

    }

};

A aa;

const A& caa =

aa;

decltype(aa.a)  // int

decltype(aa.b)   //

decltype(caa.a)  //

但内置操作符.*和->*适用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 {

        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修飾符被忽略:

i = ...;

const int j = ...;

decltype(i)&        

// int&. The redundant & is ok

const decltype(j)   // const

int. The redundant const is ok

eg10 函數調用(Rule-2)

foo();

decltype(foo())    // int

float&

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)

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>()

"const int";

string Foo<int

&>()

    return "int&";

string Foo<const int&>()

"const int&";

class A{};

Foo<A>()

    return "A";

main()

    int a;

    int &b =

    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;

<< "f: " << Foo<decltype(f)>() <<

F:\tmp>g++ decltype_eg1.cpp

-std=c++0x

F:\tmp>a.exe

a: int

b: int&

c: const

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.