【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(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),布布扣,bubuko.com

时间: 2024-10-12 20:51:54

【C++0x】表达式之类型(decltype)的相关文章

C++11:类型推导和追踪函数返回类型decltype

参考文章:https://blogs.oracle.com/pcarlini/entry/c_11_tidbits_decltype_part decltype 是 GCC 实现的第一个 C++ 11 新特性.它实际上起源于一个相当古老的 GNU 扩展关键字-- __typeof__.这个非标准关键字也能够在 C 语言中使用,GNU Compiler Collection 的专业用户可能对它更熟悉一些.2008 年,GCC 4.3.x 就实现了这个特性,同时去除了 __typeof__ 的一些缺

LINQ to Entities 不支持 LINQ 表达式节点类型“Invoke”

Expression<Func<Order_info, bool>> expre = expression; var q = db.order_info; IQueryable<Order_info> query = q; if (expre != null) { query = query.Where(expre); } 修改为: 1 Expression<Func<Order_info, bool>> expre = expression;

【java解惑】条件表达式结果类型规则

如下代码: public class Example008 { public static void main(String[] args) { char x = 'X'; int i = 0; System.out.println(true ? x : 65535); //1 System.out.println(true ? x : 65536); //2 System.out.println(true ? x : i); //3 System.out.println(false ? 0 :

无法确定条件表达式的类型,因为Datetime和&lt;null&gt;之间没有隐式转换

Q: var a=isFilter ? ta.EndDate : null; Error:无法确定条件表达式的类型,因为Datetime和<null>之间没有隐式转换 ta.EndDate是DateTime类型,不能与null选择: A: var a=isFilter ? ta.EndDate : (DateTime?)null;//加在ta.EndDate也是可以的.

LINQ to Entities 不支持 LINQ 表达式节点类型“ArrayIndex”

我就不屁话,能一张图就解决的就不说话了 2015-03-28 14:53:24,440 [10] ERROR log - System.NotSupportedException: LINQ to Entities 不支持 LINQ 表达式节点类型“ArrayIndex”. 在 System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.NotSupportedTranslator.Translate(ExpressionConverter

[深入学习C#]表达式树类型——Expression tree types

表达式树允许将 lambda 表达式表示为数据结构而非可执行代码.表达式目录树是System.Linq.Expressions.Expression< D > 形式的表达式目录树类型 (expression tree type) 的值,其中 D 是任何委托类型. 如果存在从 lambda 表达式到委托类型 D 的转换,则也存在到表达式树类型 Expression< D > 的转换.而lambda 表达式到委托类型的转换生成引用该 lambda 表达式的可执行代码的委托,到表达式树类

常见表达式返回类型 (复习)

常见表达式返回类型总结 返回类型是一个非常重要的概念,它是指一个表达式运算结果的类型. 声明变量:void 一个变量声明的表达式,返回类型是void(无返回类型). int a // 这是一条变量声明语句,该表达式无返回类型int b = 1 // 注意,这仍然是一条变量声明语句!该表达式无返回类型 变量赋值:返回类型和变量类型相同 一条变量赋值的表达式,返回类型就是该变量的类型,返回结果就是该变量的值. int a, b;double c; // 该表达式返回类型int.返回结果1a = 1;

Java自动提升表达式的类型

1.表达式中的自动类型提升: 表达式求值时,Java自动的隐含的将每个byte.short或char操作数提升为int类型,这些类型的包装类型也是可以的. 例如:short s1 = 1; s1 = s1 + 1; s1+1运算中的操作数s1会被自动提升为int类型,s1+1运算结果会成为int类型,再赋值给short类型的s1时,编译器会报告需要强制转换类型的错误.需要改为short s1=1; s1=(short)(s1+1);结果就是short类型. 例如:short s1 = 1; s1

推断类型:decltype()的简单应用

template<class T, class U> auto operator+(const Matrix<T>& a, const Matrix<U>& b) -> Matrix<decltype(T{}+U{})> { Matrix<decltype(T{}+U{})> res; for(int i=0; i!=a.rows(); ++i) for(int j=0; j!=a.cols(); ++j) res(i,j)