跟我学c++高级篇——模板元编程之一萃取和元函数

一、模板元编程和萃取

前面已经在中级篇中对模板元编程进行了一个初步的分析说明,这里就不再重复这段内容。同样,萃取技术在前面也反复的的分析过。但做为模板应用的萃取是元编程的一个重要机制,c++的STL中提供的type_traits头文件中提供了大量的相关操作。在c++语言中,元数据可以分为两大类,即类型和非类型。随着c++版本的不断迭代,这两种类型的在模板中的应用的统一化已经非常明朗。
元编程的模板代码在编译期展开的过程中,经常需要处理一些参数的类型,而c++是缺少天然RTTI的类型获得的,这就要求在元编程中广泛的使用萃取技术。元编程在编译期的展开,意味着可以把运行时的时间转移到编译期,还可以通过模板展开静态多态的应用。
但c++早期对模板元编程支持的不足,导致模板元编程基本停留在一些特定的人员和场合的应用,开发多年c++的程序员不知道元编程这个概念都不是小概率事件。但模板元编程的代码可以做到直观可见,编译时和编写时保持一致的不变性,这就使得其应用的前景还是非常不错的。

二、元函数

所谓元函数,其实就是“一个操作元数据并可以在编译期调用的函数”,它一般有下面的特点:它是一个所有参数都是类型的类模板或者其有一个“type”的可访问的嵌套结果类型的类。看到这个是不是想起了c++17中的xxxx_t,或者更早一些的直接访问的::type。
元函数一般分为普通的元函数,数值型元函数和无参元函数。元函数操作的是元数据,那么什么是元数据呢?既然元数据是在编译期运行的,那么其在编译期使用的数值即为元数据。元数据主要包括以下三类:
1、类型参数
2、非类型参数如数字类型和枚举类型
3、STL模板如std::vector等
这些内容不是一成不变的,随着c++标准的不断迭代,可能一些原来不能称之为元数据的数据成为了元数据,这个要根据标准来划定。

三、元编程

下面写一个最简单的元函数:

template <typename T>
struct typeDef
{
    using type = T;
};

template <typename T, T v>
struct valueType : typeDef<T> {
     //constexpr控制编译期
    static constexpr T value = v;
};


int  main()
{
    using tType = valueType<bool, true>;
    using fFalse = valueType<bool, false>;

    std::cout << tType::value << std::endl;
    std::cout << fFalse::value << std::endl;
    std::cout <<"first type:"<< typeid(tType).name()<<"second type:" << typeid(fFalse).name() << std::endl;
}

这个你看是不是类似于STL中的一些模板类,std::integral_constant,通过这个模板可以推导出“template using bool_constant = integral_constant<bool, B>;”,进一步推导出“true_type”和“false_type”.下面看一个复杂一些的应用:

//前向声明
template <bool b, typename T>
struct add_const_ref_impl;

//实现类
template <typename T>
struct add_const_ref
{
    using type = typename add_const_ref_impl<std::is_reference<T>::value, T>::type;
};

//非引用增加引用和const,const&
template <typename T>
struct add_const_ref_impl<false, T>
{
    using type = typename std::add_lvalue_reference<typename std::add_const<T>::type>::type;
};
//引用则去除引用返回类型
template <typename T>
struct add_const_ref_impl<true, T>
{
    using type = typename std::remove_reference<T>::type;
};

void TestAddCR()
{
    using A = int&;
    using B = int;
    using C = int const&;

    std::cout << std::is_same<B, typename add_const_ref<A>::type>::value << std::endl;
    std::cout << std::is_same<C, typename add_const_ref<B>::type>::value << std::endl;
}
int  main()
{
    TestAddCR();
    return 0;
}

这个是《c++模板元编程》的一个习题,即实现一元元函数add_const_ref,如果T为一个引用类型,则返回T,否则返回T 的const&。那个书比较老,提示还用boost::is_same来测试结果,这里都改成用STL标准库里的了。
一个函数在编写后,在实际应用的平台不同往往会产生输入的参数一致,但结果却有所不同的结果,这种现象被称为函数的副作用,而这类函数则被称为有副作用的函数。这种现象一般是因为一些环境变量或者硬件的些微不同造成的。而元函数由于是在编译期进行展开执行的,所以不会出现这种情况,所以元函数是一种没有副作用的函数。

四、总结

写到元编程,其实还是很矛盾的,毕竟元编程不是好相与的。但解决问题的手段可以很多,但目标还是不能动摇,该总结分析一下,还是要动手亲自走一次。元编程可以说是模板编程里最难理解和在一般应用中极少用的一门技术,与其在分析各种底层库时费脑筋,不如把它从基础上一点点攻克,这样再阅读一些开源的代码时就会很舒畅。有目标就好,就怕没有了目标!
为什么说矛盾呢?大牛们对元编程的态度并不一致,甚至可以说很分裂,就像光明和黑暗,一定会同时存在,只不过元编程会造成“语言的分裂”,或者说是使用元编程会形成极具个性化的风格的代码,使得代码难于维护和后续的扩展,这是不符合至少国内的一些人的目的。如果每个程序员成为了一个各自不同、不可替代的螺丝钉,对他们来说是一种灾难。
元编程系列全分解成很长的时间来完成,希望能坚持到最后。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值