威尼斯手机平台-电子正规官网登录首页

热门关键词: 威尼斯手机平台,威尼斯登录首页,威尼斯正规官网
万一从前曾经经过 rustup 安装了 Rust,编写翻译器无需完全营造信任项
分类:威尼斯电子平台

Rust 1.38 已经昭示了,Rust 1.38.0 牢固版内容如下:

Rust 1.36.0 稳固版发布了。

C++11模板元编制程序,11模板编制程序

管道编写翻译(pipelined compilation卡塔尔国

万一之前已经通过 rustup 安装了 Rust,那么能够因而以下方法赢得 Rust 1.36.0:

1.概述

  模版元编制程序(template metaprogram)是C++中最复杂也是威力最精锐的编制程序范式,它是生机勃勃种能够创制和调节造进度序的程序。模版元编制程序完全不相同于普通的运营期程序,它很奇异,因为模版元程序的实行完全部是在编写翻译期,并且模版元程序决定的数目不可能是运作时变量,只好是编写翻译期常量,不可纠正,别的它应用的语法成分也是极度有限,不可能采用运维期的豆蔻梢头部分语法,比方if-else,for等语句都不能够用。由此,模版元编制程序须求过多技术,平时必要类型重定义、枚举常量、世袭、模板偏特化等措施来合营,由此编写模版元编制程序比较复杂也相比较费力。

  将来C++11骤增了有的模板元相关的性状,既能够让我们编辑模版元程序变得更易于,还进一步巩固了泛型编制程序的力量,比如type_traits让大家无需再重新发明轮子了,给大家提供了大气方便人民群众的元函数,还提供了可变模板参数和tuple,让模版元编制程序“如虎得翼”。本文将向读者展现C++11中模版元编制程序常用的技能和切实应用。

要是想要编写翻译 crate,编写翻译器无需完全营造重视项,只须要它们的“元数据”(即类型、重视项、导出的列表卡塔尔(قطر‎,元数据在编写翻译进度开始时代生成。从 Rust 1.38.0 发轫,Cargo 将借助那黄金时代优势,生机勃勃旦元数据打算妥贴,就机关开首创设信任的 crate。

$ rustup update stable

2.模版元基本概念

  模版元程序由元数据和元函数组成,元数据正是元编制程序能够操作的数目,即C++编写翻译器在编写翻译期能够操作的数码。元数据不是运转期变量,只可以是编写翻译期常量,不能校勘,成千上万的元数占领enum枚举常量、静态常量、基本项目和自定义类型等。

  元函数是模板元编制程序中用来操作处理元数据的“构件”,能够在编写翻译期被“调用”,因为它的意义和样式和平运动作时的函数肖似,而被喻为元函数,它是元编程中最重要的构件。元函数实际表现为C++的多个类、模板类或模板函数,它的平时花样如下:

template<int N, int M>
struct meta_func
{
    static const value = N+M;
}

  调用元函数到手value值:cout<<meta_func<1, 2>::value<<endl;

  meta_func的奉行进度是在编写翻译期完毕的,实际施行顺序时,是从未有过测算动作而是径直利用编写翻译期的乘除结果的。元函数只管理元数据,元数据是编写翻译期常量和花色,所以上面包车型客车代码是编写翻译然而的:

int i = 1, j = 2;
meta_func<i, j>::value; //错误,元函数无法处理运行时普通数据

  模板元编制程序发生的源程序是在编写翻译期实践的主次,由此它首先要依据C++和模板的语法,可是它操作的指标不是运作时平时的变量,因而不能利用运转时的C++关键字(如if、else、for),可用的语法元素卓绝轻松,最常用的是:

  • enum、static const,用来定义编写翻译期的大背头常量;
  • typedef/using,用于定义元数据;
  • T、Args...,评释元数据类型;
  • template,首要用以定义元函数;
  • "::",域运算符,用于拆解深入分析类型功能域获取计算结果(元数据)。

若果模板元编制程序中须要if-else、for等逻辑时该如何是好呢?

模板元中的if-else能够通过type_traits来兑现,它不光能够在编写翻译期做推断,还足以做计算、查询、调换和采取。

模板元中的for等逻辑能够经过递归、重载、和模板特化(偏特化)等形式实现。

上面来探视C++11提供的模板元幼功库type_traits。

就算这种变动对单个 crate 的编写翻译未有别的影响,但通过测量试验,获得了一些告知,对于涉嫌多少个 crate 的创设,可为干净的和优化的营造带来大概 10~六成 的编写翻译速度 。而别的的改善并少之甚少,速度的加强决议于运维构建的硬件。

要么直接从立异页面下载。

3.type_traits

  type_traits是C++11提供的沙盘模拟经营元根基库,通过type_traits能够实今后编写翻译期总计、查询、判定、转变和选用,提供了模版元编制程序必要的一些常用元函数。上边来拜谒一些基本的type_traits的核心用法。

  最简便的三个type_traits是概念编写翻译期常量的元函数integral_constant,它的定义如下:

template< class T, T v >
struct integral_constant;

  依附这么些轻便的trait,大家得以很方便地定义编写翻译期常量,比如定义三个值为1的int常量能够如此定义:

using one_type = std::integral_constant<int, 1>;

或者

template<class T>
struct one_type : std::integral_constant<int, 1>{};

  获取常量则透过one_type::value来获取,这种概念编译期常量的艺术比较C++98/03要简单,在C++98/03中定义编写翻译期常量日常是这么定义的:

template<class T>
struct one_type
{
    enum{value = 1};
};

template<class T>
struct one_type
{
    static const int value = 1;
};

  能够看出,通过C++11的type_traits提供的五个简易的integral_constant就足以很有益于的定义编写翻译期常量,而不供给再去通过定义enum和static const变量形式去定义编写翻译期常量了,那也为定义编写翻译期常量提供了其余意气风发种方式。C++11的type_traits已经提供了编译期的true和false,是由此integral_constant来定义的:

typedef  integral_constant<bool, true> true_type;
typedef  integral_constant<bool, false> false_type;

  除了那一个大旨的元函数之外,type_traits还提供了拉长的元函数,比如用来编写翻译期剖断的元函数:

#include <iostream> #include <type_traits> int main() { std::cout << "int: " << std::is_const<int>::value << std::endl; std::cout << "const int: " << std::is_const<const int>::value << std::endl; //判别类型是不是大器晚成律 std::cout<< std::is_same<int, int>::value<<"n";// true std::cout<< std::is_same<int, unsignedint>::value<<"n";// false //添加、移除const cout << std::is_same<const int, add_const<int>::type>::value << endl; cout << std::is_same<int, remove_const<const int>::type>::value << endl; //加多援用 cout << std::is_same<int&, add_lvalue_reference<int>::type>::value << endl; cout << std::is_same<int&&, add_rvalue_reference<int>::type>::value << endl; //取公共项目 typedef std::common_type<unsigned char, short, int>::type NumericType; cout << std::is_same<int, NumericType>::value << endl; return 0; }

  type_traits还提供了编写翻译期选取traits:std::conditional,它在编写翻译期根据一个判定式选拔四个品类中的三个,和规范表明式的语义形似,相通于七个安慕希表明式。它的原型是:

template< bool B, class T, class F >
struct conditional;

用法比较简单:

#include <iostream>
#include <type_traits>

int main() 
{
    typedef std::conditional<true,int,float>::type A;               // int
    typedef std::conditional<false,int,float>::type B;              // float

    typedef std::conditional<(sizeof(long long) >sizeof(long double)),
    long long, long double>::type max_size_t;

    cout<<typeid(max_size_t).name()<<endl;  //long double
}

威尼斯电子平台,  别的三个常用的type_traits是std::decay(朽化卡塔尔(قطر‎,它对于普通档案的次序来讲std::decay(朽化)是移除引用和cv符,大大简化了大家的书写。除了平时等级次序之外,std::decay还是能用于数组和函数,具体的转换法则是那般的:

  先移除T类型的援引,获得类型U,U定义为remove_reference<T>::type。

  • 如果is_array<U>::value为 true,改良类型type为remove_extent<U>::type *。
  • 否则,如果is_function<U>::value为 true,更改类型type将为add_pointer<U>::type。
  • 否则,更正类型type为 remove_cv<U>::type。

std::decay的基本用法:

typedef std::decay<int>::type A;           // int
typedef std::decay<int&>::type B;          // int
typedef std::decay<int&&>::type C;         // int
typedef std::decay<constint&>::type D;    // int
typedef std::decay<int[2]>::type E;        // int*
typedef std::decay<int(int)>::type F;      // int(*)(int)

  std::decay除了移除普通品种的cv符的功用之外,还足以将函数类型转变为函数指针类型,进而将函数指针变量保存起来,以便在后头延迟实施,举个例子上面包车型地铁例证。

template<typename F>
struct SimpFunction
{
    using FnType = typename std::decay<F>::type;//先移除引用再添加指针

    SimpFunction(F& f) : m_fn(f){}

    void Run()
    {
        m_fn();
    }

    FnType m_fn;
};

  倘诺要保存输入的函数,则先要获取函数对应的函数指针类型,此时就能够用std::decay来收获函数指针类型了,using FnType = typename std::decay<F>::type;完成函数指针类型的概念。type_traits还提供了拿到可调用对象回来类型的元函数:std::result_of,它的中坚用法:

int fn(int) {return int();}                            // function
typedef int(&fn_ref)(int);                             // function reference
typedef int(*fn_ptr)(int);                             // function pointer
struct fn_class { int operator()(int i){return i;} };  // function-like class

int main() {
  typedef std::result_of<decltype(fn)&(int)>::type A;  // int
  typedef std::result_of<fn_ref(int)>::type B;         // int
  typedef std::result_of<fn_ptr(int)>::type C;         // int
  typedef std::result_of<fn_class(int)>::type D;       // int
}

  type_traits还提供了一个很有用的元函数std::enable_if,它应用SFINAE(substitude failure is not an error卡塔尔国天性,依据准绳选取重载函数的元函数std::enable_if,它的原型是:

template<bool B, class T = void> struct enable_if;

  根据enable_if的字面意思就能够知道,它使得函数在认清规范B仅仅为true时才使得,它的主干用法:

template <class T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type foo(T t)
{
    return t;
}
auto r = foo(1); //返回整数1
auto r1 = foo(1.2); //返回浮点数1.2
auto r2 = foo(“test”); //compile error

  在位置的事例中对模板参数T做了节制,即只可以是arithmetic(整型和浮点型)类型,假使为非arithmetic类型,则编写翻译不通过,因为std::enable_if只对满意判定式条件的函数有效,对别的函数无效。

  能够因此enable_if来贯彻编写翻译期的if-else逻辑,比如上边包车型大巴例证通过enable_if和标准决断式来将入参分为两大类,进而满意全部的入参类型:

template <class T>
typename std::enable_if<std::is_arithmetic<T>::value, int>::type foo1(T t)
{
    cout << t << endl;
    return 0;
}

template <class T>
typename std::enable_if<!std::is_arithmetic<T>::value, int>::type foo1(T &t)
{
    cout << typeid(T).name() << endl;
    return 1;
}

  对于arithmetic类型的入参则重临0,对于非arithmetic的品类则赶回1,通过arithmetic将有所的入参类型分成了两大类举办拍卖。从上边的例证还足以见见,std::enable_if可以达成强盛的重运载飞机制,因为平时必得是参数区别能力重载,固然只有重回值不一致是无法重载的,而在地点的例证中,再次来到类型相通的函数都能够重载。

  C++11的type_traits提供了近百个在编写翻译期总括、查询、决断、转变和抉择的元函数,为大家编辑元程序提供了非常的大的便利。如若说C++11的type_traits让模版元编制程序变得简单,那么C++11提供的可变模板参数和tuple则进一步加强了模版元编制程序。

mem::{uninitialized, zeroed}

此版本的亮点包含:

4.可变模板参数

  C++11的可变模版参数(variadic templates)是C++11大幅度增加的最精锐的特色之黄金时代,它对参数实行了莫斯中国科学技术大学学泛化,它能表示0到自由个数、率性档期的顺序的参数。关于它的用法和行使技能读者能够参见作者在程序猿二零一四年一月A上的篇章:泛化之美--C++11可变模版参数的妙用,这里不再赘言,这里就要呈现的怎么样依附可变模板参数完毕部分编写翻译期算法,举个例子获取最大值、决断是还是不是含有了有个别项目、依照目录查找类型、获取项目标目录和遍历类型等算法。实现这几个算法要求结合type_traits或别的C++11特色,上边来拜望那几个编译期算法是怎么达成的。

  编译期从二个整形连串中拿走最大值:

//获取最大的整数
template <size_t arg, size_t... rest>
struct IntegerMax;

template <size_t arg>
struct IntegerMax<arg> : std::integral_constant<size_t, arg>
{
};

template <size_t arg1, size_t arg2, size_t... rest>
struct IntegerMax<arg1, arg2, rest...> : std::integral_constant<size_t, arg1 >= arg2 ? IntegerMax<arg1, rest...>::value :
    IntegerMax<arg2, rest...>::value >
{
};

  这些IntegerMax的兑现选用了type_traits中的std::integral_const,它在进行参数包的进程中,不断的可比,直到全体的参数都相比完,最后std::integral_const的value值即为最大值。它的选拔十分轻松:

cout << IntegerMax<2, 5, 1, 7, 3>::value << endl; //value为7

  大家能够在IntegerMax的基本功上轻松的贯彻获取最大内部存款和储蓄器对齐值的元函数MaxAlign。

  编写翻译期获取最大的align:

template<typename... Args>
struct MaxAlign : std::integral_constant<int, IntegerMax<std::alignment_of<Args>::value...>::value>{};
cout << MaxAlign<int, short, double, char>::value << endl; //value为8
    编译判断是否包含了某种类型:
template < typename T, typename... List >
struct Contains;

template < typename T, typename Head, typename... Rest >
struct Contains<T, Head, Rest...>
    : std::conditional< std::is_same<T, Head>::value, std::true_type, Contains<T, Rest... >> ::type{};

template < typename T >
struct Contains<T> : std::false_type{};
用法:cout<<Contains<int, char, double, int, short>::value<<endl; //输出true

  这些Contains的得以达成选拔了type_traits的std::conditional、std::is_same、std::true_type和std::false_type,它的兑现思路是在开展参数包的经过中不断的可比类型是不是大器晚成致,要是大器晚成致则设置值为true,不然设置为false。

        编写翻译期获取项指标目录:

template < typename T, typename... List >
struct IndexOf;

template < typename T, typename Head, typename... Rest >
struct IndexOf<T, Head, Rest...>
{
    enum{ value = IndexOf<T, Rest...>::value+1 };
};

template < typename T, typename... Rest >
struct IndexOf<T, T, Rest...>
{
    enum{ value = 0 };
};

template < typename T >
struct IndexOf<T>
{
    enum{value = -1};
};

  用法:cout<< IndexOf<int, double, short, char, int, float>::value<<endl; //输出3

  那么些IndexOf的兑现比较轻易,在展开参数包的长河中看是否相称到特化的IndexOf<T, T, Rest...>,假若相配上则截止递归将事情未发生前的value累计起来拿到指标项指标目录地方,不然将value加1,如果具备的项目中都尚未对症用药的项目则赶回-1;

  编写翻译期遵照目录地方查找类型:

template<int index, typename... Types>
struct At;

template<int index, typename First, typename... Types>
struct At<index, First, Types...>
{
    using type = typename At<index - 1, Types...>::type;
};

template<typename T, typename... Types>
struct At<0, T, Types...>
{
    using type = T;
};
    用法:
using T = At<1, int, double, char>::type;
    cout << typeid(T).name() << endl; //输出double

  At的实现比较轻巧,只要在张开参数包的长河中,不断的将索引依次减少至0时结束就能够获得对应索引地点的档期的顺序。接下来看看哪些在编写翻译期遍历类型。

template<typename T>
void printarg()
{
    cout << typeid(T).name() << endl;
}

template<typename... Args>
void for_each() 
{
    std::initializer_list<int>{(printarg<Args>(), 0)...};
}
用法:for_each<int,double>();//将输出int double

  这里for_each的落到实处是因此初始化列表和逗号表明式来遍历可变模板参数的。

  能够见到,依据可变模板参数和type_traits以至模板偏特化和递归等情势大家能够兑现部分管用的编写翻译期算法,这个算法为我们编辑应用层品级的代码奠定了底子,后边模板元编制程序的切切实实运用少将会用到那个元函数。

  C++11提供的tuple让大家编辑模版元程序变得越来越灵敏了,在任其自流程度上升高了C++的泛型编制程序本事,上面来拜候tuple如何运用于元程序中的。

从 1.38 初步,rustc 将为使用 mem::uninitialized 或 mem::zeroed 错误初阶化的狭义类提供 lint。

Future 本性已平静

有了这种稳定,官方代表期待提供关键的 crates、库和生态系统时间来打算 async / .await

5.tuple与模版元

  C++11的tuple本人正是贰个可变模板参数组成的元函数,它的原型如下:

template<class...Types>
class tuple;

  tuple在模板元编制程序中的贰个行使场景是将可变模板参数保存起来,因为可变模板参数不能够平昔作为变量保存起来,须求依靠tuple保存起来,保存之后再在要求的时候经过一些手腕将tuple又转移为可变模板参数,这些历程有一些肖似于化学中的“氧化还原反应”。看看下边包车型地铁例证中,可变模板参数和tuple是怎么着相互调换的:

//定义整形序列
template<int...>
struct IndexSeq{};

//生成整形序列
template<int N, int... Indexes>
struct MakeIndexes : MakeIndexes<N - 1, N - 1, Indexes...>{};

template<int... indexes>
struct MakeIndexes<0, indexes...>{
    typedef IndexSeq<indexes...> type;
};

template<typename... Args>
void printargs(Args... args){
    //先将可变模板参数保存到tuple中
    print_helper(typename MakeIndexes<sizeof... (Args)>::type(), std::make_tuple(args...));
}

template<int... Indexes, typename... Args>
void print_helper(IndexSeq<Indexes...>, std::tuple<Args...>&& tup){
    //再将tuple转换为可变模板参数,将参数还原回来,再调用print
    print(std::get<Indexes>(tup)...); 
}
template<typename T>
void print(T t)
{
    cout << t << endl;
}

template<typename T, typename... Args>
void print(T t, Args... args)
{
    print(t);
    print(args...);
}

  用法:printargs(1, 2.5, “test”); //将输出1 2.5 test

  上边的例子print实际上是出口可变模板参数的原委,具体做法是先将可变模板参数保存到tuple中,然后再通过元函数MakeIndexes生成四个整形系列,这么些整形体系便是IndexSeq<0,1,2>,整形连串代表了tuple七月素的目录,生成整形类别之后再调用print_helper,在print_helper中开展那些整形种类,张开的经过中依据实际的目录从tuple中收获相应的要素,最终将从tuple中抽取来的成分构成多个可变模板参数,进而完结了tuple“还原”为可变模板参数,最后调用print打字与印刷可变模板参数。

  tuple在模板元编制程序中的别的一个利用途景是用来达成部分编译期算法,比如大面积的遍历、查找和统一等算法,完成的笔触和可变模板参数达成的编写翻译期算法肖似,关于tuple相关的算法,读者能够参照作者在github上的代码:

  上边来探视模版元的求进行使。

#[deprecated] macros

alloc crates 已稳定

在 1.36.0 早先,标准库由 std、 core和 proc_macro组成。大旨包提供了中央作用,如 Iterator 和Copy ,可以在 #![no_std] 意况中选拔,因为它未有强加任何供给。同一时间, std crate 提供相像 Box<T> 和 OS 功用的类别,但须要全局分配器和其余 OS 成效作为回报。

从 Rust 1.36.0 开始,std 的风华正茂对信任于大局分配器,例如 Vec<T>今昔得以在 alloc crate 中使用。

6.模版元的接收

  大家将呈现什么通过沙盘模拟经营元来得以达成function_traits和Vairant类型。

  function_traits用来得到函数语义的可调用对象的局地品质,比如函数类型、再次来到类型、函数指针类型和参数类型等。下边来拜望哪些促成function_traits。

template<typename T>
struct function_traits;

//普通函数
template<typename Ret, typename... Args>
struct function_traits<Ret(Args...)>
{
public:
    enum { arity = sizeof...(Args) };
    typedef Ret function_type(Args...);
    typedef Ret return_type;
    using stl_function_type = std::function<function_type>;
    typedef Ret(*pointer)(Args...);

    template<size_t I>
    struct args
    {
        static_assert(I < arity, "index is out of range, index must less than sizeof Args");
        using type = typename std::tuple_element<I, std::tuple<Args...>>::type;
    };
};

//函数指针
template<typename Ret, typename... Args>
struct function_traits<Ret(*)(Args...)> : function_traits<Ret(Args...)>{};

//std::function
template <typename Ret, typename... Args>
struct function_traits<std::function<Ret(Args...)>> : function_traits<Ret(Args...)>{};

//member function
#define FUNCTION_TRAITS(...) 
    template <typename ReturnType, typename ClassType, typename... Args>
    struct function_traits<ReturnType(ClassType::*)(Args...) __VA_ARGS__> : function_traits<ReturnType(Args...)>{}; 

FUNCTION_TRAITS()
FUNCTION_TRAITS(const)
FUNCTION_TRAITS(volatile)
FUNCTION_TRAITS(const volatile)

//函数对象
template<typename Callable>
struct function_traits : function_traits<decltype(&Callable::operator())>{};

  由于可调用对象只怕是普通的函数、函数指针、lambda、std::function和成员函数,所以大家需求针对这几个连串分别做偏特化。个中,成员函数的偏特化微微复杂一点,因为涉嫌到cv符的拍卖,这里通过定义二个宏来杀绝重复的沙盘模拟经营类定义。参数类型的拿到大家是依据tuple,将参数转变为tuple类型,然后依照目录来获得相应品种。它的用法比较轻松:

template<typename T>
void PrintType()
{
    cout << typeid(T).name() << endl;
}
int main()
{
    std::function<int(int)> f = [](int a){return a; };
    PrintType<function_traits<std::function<int(int)>>::function_type>(); //将输出int __cdecl(int)
    PrintType<function_traits<std::function<int(int)>>::args<0>::type>();//将输出int
    PrintType<function_traits<decltype(f)>::function_type>();//将输出int __cdecl(int)
}

  有了那么些function_traits和前边完结的一些元函数,我们就会方便人民群众的完结一个“万能类型”—Variant,Variant实际上三个泛化的类型,这些Variant和boost.variant的用法相通。boost.variant的骨干用法如下:

typedef variant<int,char, double> vt;
vt v = 1;
v = 'a';
v = 12.32;

  那么些variant能够肩负已经定义的那么些类型,看起来有一些相像于c#和java中的object类型,实际上variant是擦除了品种,要博取它的实际上类型的时候就稍显麻烦,要求通过boost.visitor来访谈:

威尼斯电子平台 1struct VariantVisitor : public boost::static_visitor<void> { void operator() (int a) { cout << "int" << endl; } void operator() (short val) { cout << "short" << endl; } void operator() (double val) { cout << "double" << endl; } void operator() (std::string val) { cout << "string" << endl; } }; boost::variant<int,short,double,std::string> v = 1; boost::apply_visitor(visitor, v); //将输出int View Code

  通过C++11模板元完毕的Variant将改过值的收获,将获取实际值的措施改为停放的,即经过下边包车型的士艺术来拜谒:

typedef Variant<int, double, string, int> cv;
cv v = 10;
v.Visit([&](double i){cout << i << endl; }, [](short i){cout << i << endl; }, [=](int i){cout << i << endl; },[](const string& i){cout << i << endl; });//结果将输出10

  这种艺术更便利直观。Variant的达成须要凭借前文中落到实处的风度翩翩部分元函数MaxInteger、MaxAlign、Contains和At等等。上边来探视Variant实现的最首要代码,完整的代码请读者仿照效法作者在github上的代码

威尼斯电子平台 2template<typename... Types> class Variant{ enum{ data_size = IntegerMax<sizeof(Types)...>::value, align_size = MaxAlign<Types...>::value }; using data_t = typename std::aligned_storage<data_size, align_size>::type; public: template<int index> using IndexType = typename At<index, Types...>::type; Variant(void) :m_typeIndex(typeid(void)){} ~Variant(){ Destroy(m_typeIndex, &m_data); } Variant(Variant<Types...>&& old) : m_typeIndex(old.m_typeIndex){ Move(old.m_typeIndex, &old.m_data, &m_data); } Variant(const Variant<Types...>& old) : m_typeIndex(old.m_typeIndex){ Copy(old.m_typeIndex, &old.m_data, &m_data); } template <class T, class = typename std::enable_if<Contains<typename std::remove_reference<T>::type, Types...>::value>::type> Variant(T&& value) : m_typeIndex(typeid(void)){ Destroy(m_typeIndex, &m_data); typedef typename std::remove_reference<T>::type U; new(&m_data) U(std::forward<T>(value)); m_typeIndex = type_index(typeid(U)); } template<typename T> bool Is() const{ return (m_typeIndex == type_index(typeid(T))); } template<typename T> typename std::decay<T>::type& Get(){ using U = typename std::decay<T>::type; if (!Is<U>()) { cout << typeid(U).name() << " is not defined. " << "current type is " << m_typeIndex.name() << endl; throw std::bad_cast(); } return *(U*)(&m_data); } template<typename F> void Visit(F&& f){ using T = typename Function_Traits<F>::template arg<0>::type; if (Is<T>()) f(Get<T>()); } template<typename F, typename... Rest> void Visit(F&& f, Rest&&... rest){ using T = typename Function_Traits<F>::template arg<0>::type; if (Is<T>()) Visit(std::forward<F>(f)); else Visit(std::forward<Rest>(rest)...); } private: void Destroy(const type_index& index, void * buf){ std::initializer_list<int>{(Destroy0<Types>(index, buf), 0)...}; } template<typename T> void Destroy0(const type_index& id, void* data){ if (id == type_index(typeid(T))) reinterpret_cast<T*>(data)->~T(); } void Move(const type_index& old_t, void* old_v, void* new_v) { std::initializer_list<int>{(Move0<Types>(old_t, old_v, new_v), 0)...}; } template<typename T> void Move0(const type_index& old_t, void* old_v, void* new_v){ if (old_t == type_index(typeid(T))) new (new_v)T(std::move(*reinterpret_cast<T*>(old_v))); } void Copy(const type_index& old_t, void* old_v, void* new_v){ std::initializer_list<int>{(Copy0<Types>(old_t, old_v, new_v), 0)...}; } template<typename T> void Copy0(const type_index& old_t, void* old_v, void* new_v){ if (old_t == type_index(typeid(T))) new (new_v)T(*reinterpret_cast<const T*>(old_v)); } private: data_t m_data; std::type_index m_typeIndex;//类型ID }; View Code

  实现Variant首先须要定义二个足足大的缓冲区用来存放分歧的品种的值,那些缓类型冲区实际上正是用来擦除类型,不一致的等级次序都通过placement new在这里个缓冲区上创制对象,因为项目长度差别,所以需求思谋内部存款和储蓄器对齐,C++11赶巧提供了内部存款和储蓄器对齐的缓冲区aligned_storage:

template< std::size_t Len, std::size_t Align = /*default-alignment*/ >
struct aligned_storage;

  它的率先个参数是缓冲区的长短,第一个参数是缓冲区内部存储器对齐的大大小小,由于Varaint能够担当多样类型,所以大家须要获得最大的项目长度,保障缓冲区丰盛大,然后还要获得最大的内部存款和储蓄器对齐大小,这里大家由在此早先边实现的MaxInteger和MaxAlign就能够了,Varaint中内部存款和储蓄器对齐的缓冲区定义如下:

enum
{
    data_size = IntegerMax<sizeof(Types)...>::value,
    align_size = MaxAlign<Types...>::value
};
using data_t = typename std::aligned_storage<data_size, align_size>::type; //内存对齐的缓冲区类型

  其次,大家还要落到实处对缓冲区的构造、拷贝、析议和活动,因为Variant重新赋值的时候供给将缓冲区中原来的连串析构掉,拷贝布局和活动布局时则供给拷贝和移动。这里以析构为例,大家要求依附当前的type_index来遍历Variant的全数体系,找到相应的类别然后调用该项目标析构函数。

void Destroy(const type_index& index, void * buf)
    {
        std::initializer_list<int>{(Destroy0<Types>(index, buf), 0)...};
    }

    template<typename T>
    void Destroy0(const type_index& id, void* data)
    {
        if (id == type_index(typeid(T)))
            reinterpret_cast<T*>(data)->~T();
    }

  这里,大家透过开首化列表和逗号表明式来张开可变模板参数,在拓宽的长河中寻觅对应的连串,假诺找到了则析构。在Variant布局时还亟需小心三个细节是,Variant无法接纳未有先行定义的门类,所以在构造Variant时,须要限定品种必得在预订义的项目范围在那之中,这里通过type_traits的enable_if来限制模板参数的品类。

template <class T,
    class = typename std::enable_if<Contains<typename std::remove_reference<T>::type, Types...>::value>::type> Variant(T&& value) : m_typeIndex(typeid(void)){
            Destroy(m_typeIndex, &m_data);
            typedef typename std::remove_reference<T>::type U;
            new(&m_data) U(std::forward<T>(value));
            m_typeIndex = type_index(typeid(U));
    }

  这里enbale_if的基准便是前边落成的元函数Contains的值,当未有在预订义的花色中找到相应的档期的顺序时,即Contains重回false时,编写翻译期会报三个编写翻译错误。

  最终还亟需落实内置的Vistit效能,Visit的达成需求先经过定义风姿浪漫多元的拜访函数,然后再遍历这么些函数,遍历进程中,推断函数的首先个参数类型的type_index是不是与当下的type_index雷同,假使相近则赢伏贴前项目标值。

template<typename F>
    void Visit(F&& f){
        using T = typename Function_Traits<F>::template arg<0>::type;
        if (Is<T>())
            f(Get<T>());
    }

    template<typename F, typename... Rest>
    void Visit(F&& f, Rest&&... rest){
        using T = typename Function_Traits<F>::template arg<0>::type;
        if (Is<T>())
            Visit(std::forward<F>(f));
        else
            Visit(std::forward<Rest>(rest)...);
    }

  Visit功用的兑现采取了可变模板参数和function_traits,通过可变模板参数来遍历意气风发多级的探问函数,遍历进度中,通过function_traits来博取第2个参数的品类,和Variant当前的type_index相像的则取值。为何要收获访谈函数第二个参数的档次呢?因为Variant的值是唯黄金年代的,独有三个值,所以博得的拜候函数的率先个参数的品类正是Variant中积存的对象的实际上类型。

#[deprecated] 属性最早是在 Rust 1.9.0 版本中引进的。Rust 1.38.0 扩大了质量,允许将其接受于宏,使用 deprecated 属性将宏标识为 deprecated。

MaybeUninit<T> 代替 mem::uninitialized

在 Rust 的最先版本中,mem::uninitialized 函数允许通过伪装已在品种 T 开头化值而不执行其它操作来绕过 Rust 的初阶化检查。不过mem::uninitialized 基本上不能够精确利用,因为 Rust 编写翻译器假定值已正确开头化。

为了消除这种情状,在 Rust 1.36.0 中, MaybeUninit<T> 类型已经稳定。

并且,由于 MaybeUninit<T> 是更安全的代替方案,从 Rust 1.38 初阶,函数 mem::uninitialized将被弃用。

7总结

  C++1第11中学的一些个性比方type_traits、可变模板参数和tuple让模版元编制程序变得更简明也更加结实大,模版元编制程序即使功效强大,但也比较复杂,要用好模版元,要求咱们转移观念情势,在调整宗旨的理论的根基上,再认真研讨模版元的有个别常用技能,那些技巧是有规律可循的,基本上都以因此重定义、递归和偏特化等手腕来贯彻的,当我们对这几个骨干技巧很熟练的时候再结合不断地试行,相信对模版元编制程序就能够旁逸横出“耳闻则诵”了。

 

正文曾揭橥于《技师》二零一五年二月刊。转载请注脚出处。

后记:本文的剧情入眼源于于小编在集团内部培养演练的一回课程,因为众多少人对C++11模板元编制程序掌握得不深切,所以自个儿以为有无法缺少拿出去分享一下,让更加多的人见状,就整合治理了一下发到程序员杂志了,我深信读者看完未来对模版元会有周到深远的询问。

1.概述 模版元编制程序(template metaprogram)是C++中最复杂也是威力最强盛的编制程序范式,它是风流倜傥种能够创设和操纵程序...

std::any::type_name

NLL 向后移植到 Rust 二〇一六

Rust 1.31.0 推出了 NLL(非词汇生命周期),这种语言的改正使借阅检查器变得尤为智能且进一层客商自身。比如,能够如此写:

fn main() {
    let mut x = 5;
    let y = &x;
    let z = &mut x; // This was not allowed before 1.31.0. }

在 1.31.0 中,NLL 仅在 Rust 2018 中牢固下来,并许诺会被向后移植到 Rust 二零一四。Rust 1.36.0 达成了这么些承诺,NLL 未来可用来 Rust 2014。

对此调节和测验,获取项指标称呼不经常是行得通的。举例,在通用代码中,你只怕希望在运维时观看函数的花色参数被实例化的切切实实项目,此版本能够利用 std::any::type_name 达到那少年老成急需:

一个新的 HashMap<K, V> 实现

在 Rust 1.36.0 中, HashMap<K, V> 实现已被调换为依照 SwissTable 设计的 hashbrown crate 中的达成。即便接口是相近的,但 HashMap<K, V> 达成现在平均更快并且具有更低的内部存款和储蓄器花销。需求注意的是,与 hashbrown crate 不同,std 中的达成仍默以为 SipHash 1-3 散列算法。

fn gen_value<T: Default>() -> T {
    println!("Initializing an instance of {}", std::any::type_name::<T>());
    Default::default()
}

fn main() {
    let _: i32 = gen_value();
    let _: String = gen_value();
}

Cargo 的离线援救

在 Rust 1.36 中,支持 --offline改变了 Cargo 的正视解析算法,仅使用本地缓存的依据关系。要开始时期填充本地缓存以思量脱机,请使用 cargo fetch 命令,该命令将下载项目所需的装有正视项。

威尼斯电子平台 3出口结果:

库的修改

  •  dbg! 宏未来支撑四个参数

新的协和 API 蕴含:

  • task::Waker 和 task::Poll
  • VecDeque::rotate_left 和 VecDeque::rotate_right
  • Read::read_vectored 和 Write::write_vectored
  • Iterator::copied
  • BorrowMut<str> for String
  • str::as_mut_ptr

端详可查看发表布告。

(文/开源中华夏儿女民共和国卡塔尔    

Initializing an instance of i32
Initializing an instance of alloc::string::String

威尼斯电子平台 4威尼斯电子平台 5库的变动

  • slice::{concat,connect,join} 今后协助 &[T] 和 &T
  • *const T 和 *mut T 以后落到实处 maker::Unpin
  • Arc<[T]> 和 Rc<[T]> 实现 FormIterator<T>
  • iter::StepBy,Peekble,Take 实现 DoubleEndedIterator

除此以外,以下那个意义已经平安:

  • Duration::div_duration_f32 和 Duration::div_duration_f64
  • <*const T>::cast 和 <*mut T>::cast
  • Duration::as_secs_f32 和 Duration::as_secs_f64
  • Duration::div_f32 和 Duration::div_f64
  • Duration::from_secs_f32 和 Duration::from_secs_f64
  • Duration::mul_f32 和 Duration::mul_f64 

获得 1.38 版本方式如下:

rustup update stable

威尼斯电子平台 6威尼斯电子平台 7端详见发文公告:

(文/开源中中原人民共和国卡塔尔(قطر‎    

本文由威尼斯手机平台发布于威尼斯电子平台,转载请注明出处:万一从前曾经经过 rustup 安装了 Rust,编写翻译器无需完全营造信任项

上一篇:没有了 下一篇:微软表示开源 STL,开源圈作为开发者密度最高的圈子
猜你喜欢
热门排行
精彩图文