本页使用了标题或全文手工转换

decltype

维基百科,自由的百科全书
跳转至: 导航搜索

C++程序设计语言中,decltype作为操作符英语Operator (programming),用于获取表达式数据类型C++11标准引入decltype,主要是为泛型编程而设计,以解决泛型编程中有些类型由模板参数决定而难以(甚至不可能)表示的问题。

从语义上说,decltype的设计适合于通用库编写者或编程新手。总体上说,对于变量或函数参数作为表达式,由decltype推导出的类型与源码中的定义可精确匹配。而正如sizeof英语sizeof操作符一样,decltype不对操作数求值。

设计构想[编辑]

随着C++引入模板,以及由标准模板库引领的泛型编程逐渐兴起,实现一个能获取表达式类型的机制的需求便由此出现,而这一机制常称为typeof。在泛型编程中,若类型由函数参数决定,则获知之常非易事[1][2],在需要获取函数模板实例化的返回类型时尤然[1]

为此,许多编译器厂商都基于程序语言现有的功能,自行实现了这类操作符,其实现如typeof英语typeof,以及一些功能有限,但更易移植的实现,以满足这一需求[3]。早在C++还未完全标准化的1997年,布莱恩·帕克(Brian Parker)就基于sizeof操作符,提出了一种可移植的解决方案[3]。对此,比尔·吉本斯(Bill Gibbons)则提出,这一方案仍有诸多限制,而且通常来说,直接引入typeof机制效果都更好[3]。2000年10月,安德烈·亚历山德雷斯库英语Andrei Alexandrescu在IT技术杂志《Dr. Dobb's Journal英语Dr. Dobb's Journal》上评论道:“(若)有typeof(操作符),撰写和理解模板代码就会便易许多。[4]”他也提到“typeof和sizeof(操作符)有相同的后端,(这是)因为sizeof无论如何必须去计算类型。[4]安德鲁·克尼格英语Andrew Koenig (programmer)与芭芭拉·E·摩(Barbara E. Moo)也谈到内建于程序语言中的typeof功能非常有用,但也提醒道“使用时常会引入一些难以发觉的程序错误,且尚有无法解决的问题(即并非万用)。[5]”并提出可以利用类型转换(如使用标准模板库所提供的typedef),更有效、更通用地实现这一功能[5]。但是,史蒂夫·丹斯特(Steve Dewhurst)则称如此转换“在设计与发布上花费巨大”,而且“采用直接提取表达式类型的方法更简单。[6]”(大意)2011年间,在一片关于C++0x的文章中,克尼格和摩预言道:“decltype将会广泛用于为每日的程序编写提供便利。[7]

2002年间, 比雅尼·斯特劳斯特鲁普提议扩充C++程序语言,为之引入查询表达式类型,以及不必指明类型便可初始化对象的机制[1]。斯特劳斯特鲁普注意到,在GCCEDG英语Edison Design Group编译器中,typeof所提供的“引用丢弃”(reference-dropping)语义可能存在问题[1];另一方面,若使用基于表达式左值性、返回一个引用类型的操作符实现之,又难以理解。于是,在呈交给C++标准委员会的初始提案中,便将两种实现方法杂糅起来:只有当表达式的声明类型包含一个引用时,操作符才会返回一个引用类型。为强调推导出的类型能确实反映表达式的声明类型,提案中提议将此操作符命名为decltype[1]。提案还提及了decltype的一项主要设计初衷,也即让编写完美的转发函数成为可能[8]。在编程时,程序员有时需要编写一个泛型转发函数,使之不论以何种类型实例化,都能返回同于包装函数的类型,而若无decltype操作符,就几乎不可能做到这一点[8]。decltype的样例代码如下所示,其中利用了C++11标准中的“返回类型后置”(trailing-return-type)语法[8]

int& foo(int& i);
float foo(float& f);
 
template <class T> auto transparent_forwarder(T& t)> decltype(foo(t)) {
  return foo(t);
}

decltype便是本段代码的核心部分,用于保存“包装函数是否返回一个引用类型”这一信息 [9]

语义[编辑]

类似于sizeof操作符,decltype不对其操作数求值[10]。粗略来说,decltype(e)返回类型前,进行了如下推导[1]

  • 若表达式e为一个无括号的变量、函数参数、类成员访问,那么返回类型即为该变量或参数或类成员在源程序中的“声明类型”;
  • 否则的话,根据表达式的值分类(value categories),设T为e的类型:
    • e是一个左值(lvalue,即“可寻址值”),则decltype(e)将返回T&
    • e是一个临终值(xvalue),则返回值为T&&
    • e是一个纯右值(prvalue),则返回值为T

这些语义是为满足通用库编写者的需求而设计,但由于decltype的返回类型总与对象(或函数)的定义类型相匹配,这对编程新手来说也更为直观[1]。更正式地说,规则1适用于不带括号的标识符表达式(id-expression)与类成员访问表达式[11][12]。示例如下[11][註 1]

const int&& foo();
const int bar();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1; // 类型为const int&&
decltype(bar()) x2; // 类型为int
decltype(i) x3; // 类型为int
decltype(a->x) x4; // 类型为double
decltype((a->x)) x5; // 类型为const double&

由上可见,最后两个对decltype的调用,返回结果有所不同。这是因为,带括号的表达式(a->x)既非“标识符表达式”,亦非类访问表达式,因而未指向一个命名对象[13],而是一个左值,于是推导类型便为“指向表达式类型的引用”,亦即const double&[10]

在2008年12月,雅克·雅尔维(Jaakko Järvi)向标准委员会指出一个问题:在C++中,“带限定标识符”(qualified-id)无法由decltype作成[14],而这正与“decltype(e)可作‘类型定义名’(typedef-name)看待”的设计初衷不一致[15]。在评论标准委员会为C++0xC++11前名)制定的正式草案时,日本ISO会员成员提到,“一个定义域操作符(::)不适用于decltype,但本应适用才对。(若能解决这一问题,则)这在需要从实例中获取成员类型(嵌套类型)很有用,如下所示[16]”:

vector<int> v;
decltype(v)::value_type i = 0; // int i = 0;

这一问题,以及其他相似问题(关于decltype无法在衍生类声明和析构函数调用中使用),都交由大卫·范德沃德(David Vandevoorde)处理,并在2010年3月投票纳入工作日程表[17][18]。解决办法是:如果表达式是纯用户定义类型(plain user defined type),即不是引用、指针、函数等,则decltype表达式返回类名。这意味着可以访问嵌套类型。甚至可以用decltype(expr)作为派生时的基类型。

可用性[编辑]

decltype包含于当前的C++标准C++11[11],并由许多编译器以扩展的形式提供:微软Visual C++ 2010编译器中提供了decltype操作符,基本实现了标准委员会提案中所描述的语义,并且在托管代码或原生代码中都可使用[9]。据其文档称,这一实现“主要对编写模板库的开发者有用。[9]”从2008年3月5日发布的4.3版开始[19]GCC C++编译器也加入了decltype操作符[20]。这一操作符也已纳入了Codegear英语CodegearC++ Builder 2009[21]Intel C++编译器[22]Clang[23]

注释[编辑]

  1. ^ 在示例代码中,为“bar()”推导出的类型就是纯粹的int,而非const int。这是因为,若未静态声明不同类型,则非用户定义类型的纯右值的类型常不带cv限定符(即不带const和volatile)。

参考资料[编辑]

  1. ^ 1.0 1.1 1.2 1.3 1.4 1.5 1.6 Gregor, Douglas; Järvi, Jaakko; Siek, Jeremy; Stroustrup, Bjarne. Decltype and auto. ISO/IEC JTC1/SC22/WG21 – The C++ Standards Committee. 2003-04-28 [2009-08-13]. 
  2. ^ Kalev, Danny. Clean Up Function Syntax Mess with decltype. DevX.com. 2008-05-08 [2009-09-04]. 
  3. ^ 3.0 3.1 3.2 Gibbons, Bill. A Portable "typeof" Operator. Dr. Dobb's Journal. 2000-11-01 [2009-09-03]. 
  4. ^ 4.0 4.1 Alexandrescu, Andrei. Generic<Programming>: Mappings between Types and Values. Dr. Dobb's Journal. 2000-10-01 [2009-09-03]. 
  5. ^ 5.0 5.1 Koenig, Andrew; Barbara E. Moo. C++ Made Easier: Naming Unknown Types. Dr. Dobb's Journal. 2002-02-01 [2009-09-03]. 
  6. ^ Dewhurst, Steve. Common Knowledge: A Bitwise typeof Operator, Part 1. Dr. Dobb's Journal. 2000-08-01 [2009-09-03]. 
  7. ^ Koenig, Andrew; Barbara E. Moo. 4 Useful New Features in C++0x. Dr. Dobb's Journal. 2011-07-19 [2012-01-12]. 
  8. ^ 8.0 8.1 8.2 Dos Reis, Gabriel; Järvi, Jaakko; Stroustrup, Bjarne. Decltype and auto (revision 4). ISO/IEC JTC1/SC22/WG21 – The C++ Standards Committee. 2004-10-12 [2009-09-04]. 
  9. ^ 9.0 9.1 9.2 decltype Operator. Microsoft. [2009-09-04]. 
  10. ^ 10.0 10.1 Dos Reis, Gabriel; Järvi, Jaakko; Stroustrup, Bjarne. Decltype (revision 7): proposed wording. ISO/IEC JTC1/SC22/WG21 – The C++ Standards Committee. 2007-07-18 [2009-09-04]. 
  11. ^ 11.0 11.1 11.2 Becker, Pete. Working Draft, Standard for Programming Language C++. ISO/IEC JTC1/SC22/WG21 – The C++ Standards Committee. [2009-09-04]. 
  12. ^ Miller, William M. C++ Standard Core Language Defect Reports, Revision 65. ISO/IEC JTC1/SC22/WG21 – The C++ Standards Committee. 2009-08-03 [2009-09-15]. 
  13. ^ Miller, William M. C++ Standard Core Language Closed Issues, Revision 65. ISO/IEC JTC1/SC22/WG21 – The C++ Standards Committee. 2009-08-03 [2009-09-04]. 
  14. ^ Miller, William M. C++ Standard Core Language Active Issues, Revision 66. ISO/IEC JTC1/SC22/WG21 – The C++ Standards Committee. 2009-09-29 [2009-10-03]. 
  15. ^ Dos Reis, Gabriel; Järvi, Jaakko; Stroustrup, Bjarne. Decltype (revision 6): proposed wording. ISO/IEC JTC1/SC22/WG21 – The C++ Standards Committee. 2006-11-05 [2009-10-03]. 
  16. ^ Miller, William M. C++ CD1 Comment Status. ISO/IEC JTC1/SC22/WG21 – The C++ Standards Committee. 2009-08-03 [2009-10-03]. 
  17. ^ Miller, William M. C++ Standard Core Language Defect Reports, Revision 69. ISO/IEC JTC1/SC22/WG21 – The C++ Standards Committee. 2010-03-29 [2010-04-10]. 
  18. ^ Vandevoorde, Daveed. Core issues 743 and 950: Additional decltype(...) uses. ISO/IEC JTC1/SC22/WG21 – The C++ Standards Committee. 2010-02-03 [2010-04-10]. 
  19. ^ GCC 4.3 Release Series. Free Software Foundation. 2009-08-13 [2009-09-04]. 
  20. ^ C++0x Support in GCC. Free Software Foundation. 2009-08-27 [2009-09-04]. 
  21. ^ Type Specifier decltype (C++0x). Embarcadero Technologies. [2009-09-04]. 
  22. ^ std, Qstd. Intel Corporation. [2009-09-04]. 
  23. ^ Gregor, Douglas. New C++0x feature support in Clang. 2011-01-26. 

外部链接[编辑]