【C++0x】表达式之类型(decltype)

简介: C++0x引入了新的关键字decltype,它是一个操作符,用来取得表达式的类型,主要在泛型编程中使用。这里,简单介绍一下语法规则。语法形式:decltype (expression)其中,这里的括号必不可少(这点不同于sizeof操作符)。
 
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.
相关文章
|
25天前
|
算法 程序员 C语言
【C++ 随机数分布类型 】深入探索C++随机数分布:原理、应用与实践(二)
【C++ 随机数分布类型 】深入探索C++随机数分布:原理、应用与实践
54 0
【C++ 随机数分布类型 】深入探索C++随机数分布:原理、应用与实践(二)
|
30天前
|
XML 安全 C++
DBus类型系统以及在Qt和C++ 中的使用(二)
DBus类型系统以及在Qt和C++ 中的使用
41 0
|
30天前
|
XML 存储 Unix
DBus类型系统以及在Qt和C++ 中的使用(一)
DBus类型系统以及在Qt和C++ 中的使用
33 0
|
25天前
|
算法 编译器 数据库
【C++ 泛型编程 高级篇】使用SFINAE和if constexpr灵活处理类型进行条件编译
【C++ 泛型编程 高级篇】使用SFINAE和if constexpr灵活处理类型进行条件编译
243 0
|
25天前
|
机器学习/深度学习 算法 编译器
【C++ 泛型编程 中级篇】深度解析C++:类型模板参数与非类型模板参数
【C++ 泛型编程 中级篇】深度解析C++:类型模板参数与非类型模板参数
46 0
|
25天前
|
设计模式 程序员 C++
【C++ 泛型编程 高级篇】C++模板元编程:使用模板特化 灵活提取嵌套类型与多容器兼容性
【C++ 泛型编程 高级篇】C++模板元编程:使用模板特化 灵活提取嵌套类型与多容器兼容性
241 2
|
25天前
|
存储 JSON 安全
【C++ 泛型编程 综合篇】泛型编程深度解析:C++中的五种类型泛型策略综合对比
【C++ 泛型编程 综合篇】泛型编程深度解析:C++中的五种类型泛型策略综合对比
65 1
|
9天前
|
编译器 C语言 C++
C++ lambda表达式
C++ lambda表达式
|
23天前
|
算法 安全 编译器
【C++ 17 新特性 折叠表达式 fold expressions】理解学习 C++ 17 折叠表达式 的用法
【C++ 17 新特性 折叠表达式 fold expressions】理解学习 C++ 17 折叠表达式 的用法
23 1
|
25天前
|
算法 测试技术 编译器
【C++ 基本类型 bool 】深入探索C++中的布尔类型Boolean(二 )
【C++ 基本类型 bool 】深入探索C++中的布尔类型Boolean
25 0