【译】VC10中的C++0x特性 part 3 : 声明之类型

【译】VC10 中的 C++0x 特性 part 3 : 声明之

来源:vcblog  翻译:飘飘白云 [email protected]  

(转载时请注明作者和出处。未经许可,请勿用于商业用途)


简介

这一系列文章介绍Microsoft Visual Studio 2010 中支持的C++ 0x特性,目前有三部分。
Part 1 :介绍了Lambdas, 赋予新意义的auto,以及 static_assert;
Part 2( 一 , 二 ):介绍了右值引用(Rvalue References);
Part 3 :介绍了表达式类型(decltype)

 

VC10中的C++0x特性 Part 1,2,3 译文打包下载(doc 和 pdf 格式): 点此下载

 

本文是Part 3。


今天我要 decltype ,它 完美 转发 函数能 返回任意 型的 西。 对编 写高度泛型的人来 说这 是很有趣的的特性。

 

返回 问题

C++98/03 有一个有意思的盲点: 定一个像 x * y 的表达式, x y 是任意 型,你却没法知道 x * y 型。假如 x Watts 型的, y Seconds 型的,那 x * y 型可能会是 Joules 型的。 定声明 print(const T& t) print( x * y ) ,在 T 会被推 导为 Joules 型。但反 来却不是 这样 的:当你写个函数 multiply(const A& a, const B& b) ,你无法指定它的通用返回 型。即使是 例化成 multiply<A, B>() 编译 器也 x * y 型,但你就是没 法得到那 的信息(指返回 型)。 C++0x 中的 关键词 decltype 除了 个盲点, 你能 够说 multiply() 返回 x * y 型的 西 。( decltype "declared type" 写,我把它 “speckle type” 。)

 

decltype :模式

下面是一个完全泛化的封装 +() 操作符的函数因子。 加法 因子不是一个模板,但它有一个模板函数, 个模板函数 两个任意 型(当然是不同 型的)参数,并把它 想加,然后返回任意 型(可能跟两个参数的 型完全不同)的 果。

 

C:/Temp>type plus.cpp

#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;

}

 

C:/Temp>cl /EHsc /nologo /W4 plus.cpp

plus.cpp

 

C:/Temp>plus

41 52 63

cute fluffy kittens

 

C++98/03 <functional> 中的 std::plus<T> ( C++0x 没有 变动 ) 来作 比,后者是一个 模板,你不得不 传递 模板参数 型来 plus<int>() plus<string>() ,重 声明一次元素 型。并且后者那个形式 T operator()(const T& x, const T& y) 的非模板函数 用操作符,如果不借助于 转换 ,就不能将两 不同 型的 西相加,更不用 3 不同 型的情况了( 注:两个参数 + 一个返回 型)。(你可以 传递 string const char * 型的 参来 const plus<string>() ,那 就会在串接操作之前,基于第二个参数 (const char * ) 构建一个 临时 string 这样 做在性能上不可取)。 再者,因 它的参数是 const T& 形式的, 就不能使用 C++0x move 意来 得好 Plus 避免了上述 问题 Plus() 不需要重 声明元素的 型,它也可以 “3 不同 型的情况,并且它用了完美 转发 ,因而能 使用 move 意。

 

trailing return type

 

再来看看 个模板函数 用操作符:

 

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);

}

里的 auto for ( auto i = v.begin(); i != v.end(); ++i) 中的含 完全不同 , for 中它是指 把用来初始化 象的 型当做 象的 ,而在 里它是指 个函数有 trailing-return-type ,只有指定 参之后,才能确定它返回什 么类 ”(C++0x 提案 N2857 中把 个称作 late-specified return type ,但它将被重命名 trailing-retrun-type (提案 N2859 ) 里看起来和 lambda 函数是如何指定返回 型的很相似,其 就是一 的。 lambda 函数的返回 型必 lambda 引符 [] 之后(右 )。在 里, decltype-powered 型也必 在函数参数 t u 之后(右 )。 autoT U 它是可 的,但是函数参数 t u 不可 就是 需要 decltype 的原因。(从技 上来 decltype(forward<T>(*static_cast<T *>(0)) + forward<U>(*static_cast<U *>(0)) 可以在左 ,但那看起来会 人不舒服)。

 

至于在返回 句中 要使用与 传给 decltype 的表达式相同的形式,是 了确保在任何情况下都能正确工作。(突 击测验 decltype(t + u) 就不 呢?)。 里的重 是不可避免的,但因 集中 - 只出 一次且代 位置靠近,所以不会有什

 

另一个例子

到例子的完整性,下面是一个 “3 不同 型的示例:  

 

C:/Temp>type mult.cpp

#include <algorithm>

#include <iostream>

#include <iterator>

#include <ostream>

#include <utility>

#include <vector>

using namespace std;

 

struct Multiplies {

    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);

    }

};

 

class Watts {

public:

    explicit Watts(const int n) : m_n(n) { }

    int get() const { return m_n; }

private:

    int m_n;

};

 

class Seconds {

public:

    explicit Seconds(const int n) : m_n(n) { }

    int get() const { return m_n; }

private:

    int m_n;

};

 

class Joules {

public:

    explicit Joules(const int n) : m_n(n) { }

    int get() const { return m_n; }

private:

    int m_n;

};

 

Joules operator*(const Watts& w, const Seconds& s) {

    return Joules(w.get() * s.get());

}

 

int main() {

    vector<Watts> w;

    w.push_back(Watts(2));

    w.push_back(Watts(3));

    w.push_back(Watts(4));

 

    vector<Seconds> s;

    s.push_back(Seconds(5));

    s.push_back(Seconds(6));

    s.push_back(Seconds(7));

 

    vector<Joules> j;

 

    transform(w.begin(), w.end(), s.begin(), back_inserter(j), Multiplies());

 

    for_each(j.begin(), j.end(), [](const Joules& r) { cout << r.get() << endl; });

}

 

C:/Temp>cl /EHsc /nologo /W4 mult.cpp

mult.cpp

 

C:/Temp>mult

10

18

28

 

你可能会 所有的 理真的有必要 ,答案是 Yes ,有必要。我已 了完美 转发 decltype 是如何 运算函数因子使用起来更容易(不用重 声明元素 型),更灵活(可以混合使用不同的参数和返回 型),更有效率(使用 move 意)。最重要的是,完美 转发 decltype 你能 够编 写更 简洁 明了的代 ,而不灵活和低效的代 不是 简洁 明了的 - 点是我 无法忽 的。

 

级规则

decltype 是有一些 规则 驱动 的。然而,如果你遵照上面的模式就没 系,能正常工作。我很少那 样说 C++ ,但是在 里是 这样 的。

 

然大多数 decltype 用遵循上面介 的模式,但 decltype 可以用于其他 境。在那些情况下,你就用到了 decltype 的高 模式,你 应该 全面地 阅读 那些 规则 ,它 C++0x 提案 N2857   7.1.6 .2 [dcl.type.simple]/4 中被 出。

等等, 有一些要

decltype 是第五个且是最后一个添加到 VC10 中的 C++0x 核心 言特性。 VC10 CTP 没有,但 VC10 Bata 1 中会有。而且 VC10 Beta 1 有很多 C++0x 特性,我会在后 文章中介

 

Stephan T. Lavavej

Visual C++ Libraries Developer

Published Wednesday, April 22, 2009 10:06 AM by vcblog

飘飘白云

 

( 转载时请 注明作者和出 。未 经许 可, 勿用于商 用途 )

 

ß 全文完 à

 

你可能感兴趣的:(Algorithm,C++,String,iterator,lambda,iostream)