解密:VC10中的C++ 0x特性,第3部分

第1部分 本系列的 兰巴斯 , 汽车 ,和 静态u断言 .

null

第2部分 本系列的 R值引用 ,使 移动语义 完美转发 .

今天,我要谈谈 脱模 ,它允许完美的转发函数具有任意返回类型。  对于编写高度泛型代码的人来说,这很有意思。

返回型问题

C++ 98/03有一个有趣的盲点-给定表达式 x*y轴 ,在哪里 y 有任意类型,就没有办法说“类型 x*y轴 “.  如果 属于类型 瓦特 y 属于类型 ,那么 x*y轴 可能属于 焦耳 .  鉴于 打印(常量T&T) ,您可以拨打 打印(x*y) ,和 T 将被推断为 焦耳 ,但这并不是反过来的:在写作的时候 乘法(常数A和A,常数B和B) ,则不能在保留完全通用性的情况下命名其返回类型。  即使什么时候 () 被实例化时,编译器知道 x*y轴 ,您在此无法获取该信息。  C++ 0x关键字 脱模 消除这个盲点,让你说 乘法() 返回类型 x*y轴 “.  ( 脱模 是“声明类型”的缩写;我把它读成押韵的“斑点型”。)

decltype:模式

下面是如何编写一个完全通用的函子 运算符+() .  这个 functor不是模板,但它有一个模板化的函数调用运算符,它接受任意(可能不同)类型的两个参数,将它们相加,并返回结果,结果可以是任意(可能不同于两个参数)类型。

C:温度>类型plus.cpp

#包含<算法>

#包括

#包括

#包括

#包括

#包括

#包括

使用名称空间标准;

结构升级版{

模板

汽车 运算符()(T&&T,U&&U)常量

->decltype(向前(T)+向前(U)) {

向前返回(T)+向前(U);

}

};

int main(){

向量i;

i、 向后推(1);

i、 向后推(2);

i、 推回(3);

向量j;

j、 推回(40);

j、 推回(50);

j、 推回(60);

向量k;

向量s;

s、 向后推(“切”);

s、 向后推(“流感”);

s、 向后推(“套件”);

向量t;

t、 向后推(“e”);

t、 向后推(“ffy”);

t、 向后推(“十”);

向量u;

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

转换(s.begin()、s.end()、t.begin()、back_inserter(u)、Plus());

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

不能<

对于_each(u.begin(),u.end(),[](const string&r){cout<

不能<

}

C:温度>cl/EHsc/nologo/W4 plus.cpp

加号.cpp

C:温度>正

41 52 63

可爱的毛茸茸的小猫

将此与C++ 98/03 <函数>进行比较 标准::加 (在C++ 0x中没有变化)。  因为它是一个类模板,所以你必须通过 加上() 加上() ,重复元素类型。  其非模板函数调用运算符的形式为 T运算符()(const T&x,const T&y)const ,使它无法处理2种不同的类型,更不用说3种不同的类型,而不诉诸隐式转换。  (你可以吃东西 加上() 一串 和一个 常量字符* .  这将建立一个临时的 一串 从第二个参数开始,在连接这两个参数之前 一串 s。  这样的性能不是特别理想。)  最后,因为它需要 常数T& 它不能利用C++ 0x移动语义。 避免所有这些: 加号() 不重复元素类型,它处理“3种不同类型”的情况,并且因为它使用完美转发,所以它尊重移动语义。

尾随返回类型

现在,让我们再看看模板化的函数调用操作符:

模板

汽车 运算符()(T&&T,U&&U)常量

->decltype(向前(T)+向前(U)) {

向前返回(T)+向前(U);

}

在这里, 汽车 与…有不同的含义 for(自动i=v.begin();我!=v、 结束()++(一) ,它说“使这个东西的类型与初始化它的类型相同”。  当用作返回类型时, 汽车 表示“此函数具有 尾随返回类型 ; 在我声明了它的参数之后,我将告诉您它的返回类型是什么”。  (C++ 0x工作草案 2857奈米 称之为 延迟指定返回类型 ,但这将被重命名为 尾随返回类型 ; 见文件 2859奈米 .)  如果这看起来与lambda的显式返回类型相似,那是因为事实如此。  lambda的返回类型必须位于右侧,以便 lambda介绍人 [] 先出现。  这里,那个 脱模 -函数参数的返回类型必须在右边 t型 u 先申报。  在哪里 汽车 显示在左侧,模板参数 T U 是可见的,但函数参数 t型 u 现在还看不见,这就是为什么 脱模 需要。  (从技术上讲, decltype(向前(*静态U cast(0))+向前(*静态U cast(0))) 可以往左边走,但那是个怪物(掌声)

至于表达给 脱模 ,给出了与 返回 语句确保了所有情况下的正确性。  (小测验:你为什么要这样做 数据类型(t+u) 是不是错了?)  这里的重复是不可避免的,但却是集中的——它只出现一次,在相邻的线路上,所以并不危险。

另一个例子

为了完整起见,下面是“3种不同类型”的示例:

C:温度>类型mult.cpp

#包含<算法>

#包括

#包括

#包括

#包括

#包括

使用名称空间标准;

结构倍数{

模板

自动运算符()(T&&T,U&&U)常量

->decltype(向前(T)*向前(U)){

向前返回(T)*向前(U);

}

};

瓦特级{

公众:

显式瓦特(const int n):mu n(n){}

int get()const{return mu n;}

私人:

国际货币基金组织;

};

班级秒数{

公众:

显式秒(const int n):mu n(n){}

int get()const{return mu n;}

私人:

国际货币基金组织;

};

类焦耳{

公众:

显式焦耳(const int n):m_

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享