decltype的使用

C++中, decltype作为 操作符,用于查询 表达式的数据类型。decltype在 C++11标准制定时引入,主要是为 泛型编程而设计,以解决泛型编程中,由于有些类型由模板参数决定,而难以(甚至不可能)表示之的问题。
泛型编程在整个1990年代越发流行,对实现类型推导机制的需求也应运而生。为此,许多编译器厂商都基于程序语言现有的功能,自行实现了这类操作符,其实现如typeof,以及一些功能有限,但更易移植的实现。2002年间, 比雅尼·斯特劳斯特鲁普提议在C++内标准化这类操作符,并将之加入C++;且建议命之为“decltype”,以反映其具有获取表达式的“声明类型”(Declared Type)的功能。

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

类似于sizeof 操作符,decltype也不需对其 操作数求值。粗略来说,decltype(e)返回类型前,进行了如下推导:
  1. 若表达式e指向一个 局部变量命名空间作用域变量、 静态成员变量或函数参数,那么返回类型即为该变量(或参数)的“声明类型”;
  2. 若e是一个 左值(lvalue,即“可寻址值”),则decltype(e)将返回T&,其中T为e的类型;
  3. 若e是一个x值(xvalue),则 返回值为T&&;
  4. 若e是一个纯 右值(prvalue),则返回值为T。
这些语义是为满足通用库编写者的需求而设计,但由于decltype的返回类型总与对象(或函数)的定义类型相匹配,这对编程新手来说也更为直观。更正式地说,规则1适用于不带括号的标识符表达式(id-expression)与类成员访问表达式。示例如下:
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)既非“标识符表达式”,亦非类访问表达式,因而未指向一个命名对象,而是一个 左值,于是推导类型便为“指向表达式类型的引用”,亦即const double&。
在2008年12月,雅克·雅尔维(Jaakko Järvi)向标准委员会指出一个问题:在C++中,“带限定标识符”(qualified-id)无法由decltype作成,而这正与“decltype(e)可作‘类型定义名’(typedef-name)看待”的设计初衷不一致。在评论标准委员会为 C++0xC++11前名)制定的正式草案时,日本ISO会员成员提到,“一个定义域 操作符(::)不适用于decltype,但本应适用才对。(若能解决这一问题,则)这在需要从实例中获取成员类型( 嵌套类型)很有用,如下所示”:
vector<int> v;decltype(v)::value_type i = 0; // int i = 0;
这一问题,以及其他相似问题(关于decltype无法在 派生类声明和 析构函数调用中使用),都交由大卫·范德沃德(David Vandevoorde)处理,并在2010年3月投票纳入工作日程表。
#include <algorithm>

#include <iostream>

#include <iterator>

#include <ostream>

#include <string>

#include <utility>

#include <vector>

using namespace std;

struct Plus {

template <typename T, typename U>

auto operator()(T&& t, U&& u) const

-> decltype(forward<T>(t) + forward<U>(u)) {

return forward<T>(t) + forward<U>(u);

}

};

int main() {

vector<int> i;

i.push_back(1);

i.push_back(2);

i.push_back(3);

vector<int> j;

j.push_back(40);

j.push_back(50);

j.push_back(60);

vector<int> k;

vector<string> s;

s.push_back("cut");

s.push_back("flu");

s.push_back("kit");

vector<string> t;

t.push_back("e");

t.push_back("ffy");

t.push_back("tens");

vector<string> u;

transform(i.begin(), i.end(), j.begin(), back_inserter(k), Plus());

transform(s.begin(), s.end(), t.begin(), back_inserter(u), Plus());

for_each(k.begin(), k.end(), [](int n) { cout << n << " "; });

cout << endl;

for_each(u.begin(), u.end(), [](const string& r) { cout << r << " "; });

cout << endl;

}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值