C++模板Trait

C++萃取 C++萃取是一种用于从类型中"萃取"(提取)信息的技术,通常通过模板特化实现。获取类型的特性根据类型选择不同的算法为不同类型提供统一的接口// 迭代器萃取示例// 使用Iterator自身定义的类型// 为原生指针特化的萃取// 基于萃取的泛型函数// 使用萃取获取迭代器的值类型std::cout << "处理的元素类型大小: " << sizeof(value_type) << " 字节" << std::endl;// 使用迭代器处理元素...for ( 阅读详情

转载:http://www.cnblogs.com/stephen-liu74/archive/2012/08/12/2635583.html

一直感觉c++ effective 讲的不是很明白,而这篇文章讲的通俗易懂

 Trait是C++模板设计的一个基本应用技巧,通过应用Trait模板参数,可以在工业强度的程度设计中既保证了程序的灵活性,同时也有效的减少了类型参数的数量。对于普通函数而言,如果想要对该函数的功能进行更为细粒化的控制,一个主要的方法便是为该函数增加更多的参数,而函数体内的逻辑代码则会根据参数值的不同而选择不同的逻辑分支,最终返回不同的结果。一个极端的现象是函数的参数过多,而且并不是每个参数都会为每个调用者所用,如果简单的使用缺省值,那么这些缺省参数则必须位于函数参数的末尾。如果有朝一日需要新增函数参数,而该参数恰恰又没有缺省值,此时我们只能将该新增的参数放到所有缺省参数的前面,一旦如此,已有的函数调用者都将不得不进行相应的修改以适应该函数签名的改变。同时随着参数的增多,也会给调用者带来额外的负担。一个更好的方法是将函数参数改为结构体的字段,而函数的参数也调整为该结构体的指针或者引用。相比于此,Trait模板类可以被视为刚刚提到的结构体,但是不同的是该Trait类的行为需要依赖另外一个模板参数,既当前类的主模板参数。为了更好的理解Trait在模板中的应用场景,我们先给出一个简单的示例,并再一步一步将其改造为对Trait的应用,我想这样将更加便于大家的理解。
    这里是一个非常简单的例子,但是却非常适合Trait的学习。该示例函数的主要功能是遍历模板参数类型的数组,并逐个累加每一个元素同时返回最后的累加值。

按 Ctrl+C 复制代码
#include <stdio.h>
    
    template<typename T>
    T accumulate(T const* begin, T const* end) {
        T total = T();
        while (begin != end) {
            total += *begin;
            ++begin;
        }
        return total;
    }
    
    int main() {
        int test[5] = {1,2,3,4,5};
        char chartest[] = "templates";
        int r = accumulate(test,test + 5);
        int r2 = accumulate(chartest, chartest + sizeof(chartest));
        printf("r is %d\n",r);
        printf("r2 is %d\n",r2);    
        return 0;
    }
    //r is 15
    //r2 is -49
对于上例的输出结果,r2的值可能并不是我们想要的,那么为什么会出现这样的结果呢?很简单,在第二次调用模板函数accumulate的时候,模板参数被推演成char,而char的最大值为127,因此total的结果一旦超过该值就会变为负数。为了解决该问题,我们将不得不引入更多的模板参数作为函数的返回值类型,而返回值是不会参与类型推演的,所以在使用时就必须显示指定该模板参数的实际类型。当然,我们也可以通过为主模板参数T引入一个与其关联的trait模板类来解决该问题。见如下代码和关键性注释。
按 Ctrl+C 复制代码
#include <stdio.h>
    
    template<typename T>
    class AccumulationTraits;  //该类为trait模板类的基础模板类,由于不会真实的使用,因此不需要定义。
    
    //下面是针对每一个数值型的原始类型都特化了一个Trait模板类,这样编译器在实例化accumulate函数时
    //会根据其类型参数的不同选择不同的特化Trait类。
    template<>
    class AccumulationTraits<char> {
    public:
        typedef int AccT;
    };
    
    template<>
    class AccumulationTraits<short> {
    public:
        typedef int AccT;
    };
    
    template<>
    class AccumulationTraits<int> {
    public:
        typedef long long AccT;
    };
    
    template<>
    class AccumulationTraits<unsigned int> {
    public:
        typedef unsigned long long AccT;
    };
    
    template<>
    class AccumulationTraits<float> {
    public:
        typedef double AccT;
    };
    
    //这里将该函数的返回值类型改为主模板参数T的trait类的指定属性。
    template<typename T>
    typename AccumulationTraits<T>::AccT accumulate(T const* begin, T const* end) {
        typedef typename AccumulationTraits<T>::AccT AccT;
        AccT total = AccT();
        while (begin != end) {
            total += *begin;
            ++begin;
        }
        return total;
    }
    
    int main() {
        int test[5] = {1,2,3,4,5};
        char chartest[] = "templates";
        int r = accumulate(test,test + 5);
        int r2 = accumulate(chartest, chartest + sizeof(chartest));
        printf("r is %d\n",r);
        printf("r2 is %d\n",r2);    
        return 0;
    }    
    //r is 15
    //r2 is 975 尽管通过Trait解决了返回值越界的问题,但是上面的代码示例仍然存在一些问题,如:AccT total = AccT(),这行代码要求AccT类型必须是原始类型,或者是有缺省构造的类类型,否则将会导致编译错误。在这里,我们可以进一步升级Trait类,以便accumulate函数能够通过Trait的一个属性获得total的缺省初始值。如:
复制代码
 1     #include <stdio.h>
 2     
 3     template<typename T>
 4     class AccumulationTraits;
 5     
 6     //相比于上面的示例,该示例为每一个trait的特化类都新增了一个属性,即zero()函数,用来表示
 7     //AccT类型的缺省初始值。这里之所以用zero函数,而不是普通的常量值,是因为C++中要求const
 8     //限定符修饰的成员变量只能是整数类型或枚举类型,而不能是浮点或其他自定义类型。
 9     template<>
10     class AccumulationTraits<char> {
11     public:
12         typedef int AccT;
13         static AccT zero() { return 0; }
14     };
15     
16     template<>
17     class AccumulationTraits<short> {
18     public:
19         typedef int AccT;
20         static AccT zero() { return 0; }
21     };
22     
23     template<>
24     class AccumulationTraits<int> {
25     public:
26         typedef long long AccT;
27         static AccT zero() { return 0; }
28     };
29     
30     template<>
31     class AccumulationTraits<unsigned int> {
32     public:
33         typedef unsigned long long AccT;
34         static AccT zero() { return 0; }
35     };
36     
37     template<>
38     class AccumulationTraits<float> {
39     public:
40         typedef double AccT;
41         static AccT zero() { return 0; }
42     };
43     
44     template<typename T>
45     typename AccumulationTraits<T>::AccT accumulate(T const* begin, T const* end) {
46         typedef typename AccumulationTraits<T>::AccT AccT;
47         AccT total = AccumulationTraits<T>::zero();
48         while (begin != end) {
49             total += *begin;
50             ++begin;
51         }
52         return total;
53     }
复制代码

    相比于之前的代码,上述示例尽管已经有了很大的改进,但是仍然存在一个明确的缺陷。在有些情况下,我们希望accumulate函数能够使用我们自定义的Trait类,而不是之前已经定义的一组AccumulationTrait模板类,为了解决这一问题,可以考虑为该函数增加一个模板参数,即Trait的类型,同时也为该模板参数提供缺省值,即AccumulationTrait。然而事与愿违,C++的标准并不允许模板函数包含缺省模板参数,因此我们不得不进行必要的变通,即将accumulate函数改为模板类的静态成员函数,如:

复制代码
 1     template<typename T, typename AT = AccumulationTraits<T> >
 2     class Accum {
 3     public:
 4         static typename AT::AccT accumulate(T const* begin, T const* end) {
 5             typename AT::AccT total = AT::zero();
 6             while (begin != end) {
 7                 total += *begin;
 8                 ++begin;
 9             }
10             return total;
11         }
12     };
13     //由于模板类在实例化的过程中无法根据参数进行类型推演,因此这里我们提供了一个模板
14     //函数便于调用者的使用,又因为在大多数情况下我们都会使用缺省trait,只有在个别的
15     //情况下才会考虑使用自定义的trait类,因此我们提供的第一个辅助函数将仅包含一个模板参数。
16     template<typename T>
17     typename AccumulationTrait<T>::AccT accumulate(T const* begin, T const* end) {
18         return Accum<T>::accumulate(begin,end);
19     }
20     //这里提供的第二个辅助函数,将允许调用者使用自定义的Trait类,这里之所以将T作为第二个
21     //参数,是因为该类型可以通过函数的参数推演出来,因此调用者在使用时可以不用显示指定该
22     //模板参数的实际类型,而是直接通过函数参数进行推演即可。凡是使用该辅助函数的调用者,
23     //都是希望提供自定义的Trait类,否则就会直接调用上一个辅助函数。
24     template<typename Traits,typename T>
25     typename Traits::AccT accumulate(T const* begin, T const* end) {
26         return Accum<T, Traits>::accum(begin,end);
27     }
复制代码
MOSFET开关损耗全面讲解:从原理到优化策略 深入剖析MOSFET开关损耗的产生机制,结合实际应用场景,讲解如何通过驱动设计和电路优化降低损耗,提升系统效率。重点关注mosfet在高频开关下的表现与热管理。 阅读详情

相关推荐

IDEA 导入 jbolt项目(实验室非公开项目)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录准备一、准备数据库二、IDEA导入jbolt项目 准备 在实验室群文件中下载jbolt.zip和mysql.sql两个文件 将其解压到自己的目录下 一、准备数据库 打开Navicat新建一个jbolt数据库(字符集为utf8) 导入mysql.sql文件 数据库导入完毕 二、IDEA导入jbolt项目 点击打开一个项目 选择jbolt文件夹 以Maven形式打开 打开pom.xml 在里面添加jetty-server依赖

weixin_44094842的博客 973

C++ 的 traits 技术到底是什么?

C++ 的 traits 技术,是一种约定俗称的技术方案,用来为同一类数据(包括自定义数据类型和内置数据类型)提供统一的类型名(traits),这样可以统一的操作函数,例如 advance(), swap(), encode()/decode() 等。 问题描述 首先来看 traits 技术可以解决什么问题,我们拥有自定义类型 Foo, Bar,以及编译器自带类型 int, double, string,我们想要为这些不同的类型提供统一的编码函数 decode() ,该怎样实现呢? 解决方案 方案一:函数重

于小咸的博客 1953

LabVIEW QMH模板实战:从创建到错误处理的完整指南

本文提供LabVIEW QMH模板从创建到错误处理的完整实战指南。详细解析了队列消息处理器(QMH)作为LabVIEW核心设计模式如何实现任务解耦与异步通信,涵盖事件处理循环、消息处理循环的搭建、用户事件创建、队列引用管理、消息优先级控制以及健壮的错误处理机制,帮助开发者构建稳定、可维护的复杂应用程序。

white的博客 725

萃取(traits)编程技术的介绍和应用

引子 最近在写C++代码的时候, 经常能使用到萃取(traits)编程技术, 于是学习STL中关于萃取的知识, 并总结出来, 以飨读者, 同时加深自己的理解. 迭代器中萃取技术 STL简述 STL(Standard Template Library)是C++泛型编程(template技术)的集大成者, 迭代器在STL中发挥重要的作用. 在STL中有3个重要的概念: 容器, 包括顺

shengxiaweizhi的专栏 1222

FPGA+CMV4000实战:从零搭建20fps成像系统的5个关键步骤(附避坑指南)

本文详细介绍了如何从零搭建基于FPGA和CMV4000传感器的20fps成像系统,涵盖硬件选型、SPI通信优化、LVDS数据采集、DDR2内存管理及系统集成等5个关键步骤。特别针对CMV4000传感器的SPI配置和高速数据处理的常见问题提供实用解决方案,帮助开发者避免常见陷阱,提升成像系统性能。

weixin_42628688的博客 427

primetime如何做voltage scaling

存在这样的情况,标准单元库只有ssgnp0p72vm40c和ssgnp0p9vm40c的libs,但是我们希望它工作在ssgnp0p76vm40c,这样的话就需要用ssgnp0p72vm40c和ssgnp0p9vm40c的libs来scaling出ssgnp0p76vm40c的lib。

qq_34326957的博客 1683

Step By Step(C++模板Trait)

Trait是C++模板设计的一个基本应用技巧,通过应用Trait模板参数,可以在工业强度的程度设计中既保证了程序的灵活性,同时也有效的减少了类型参数的数量。对于普通函数而言,如果想要对该函数的功能进行更为细粒化的控制,一个主要的方法便是为该函数增加更多的参数,而函数体内的逻辑代码则会根据参数值的不同而选择不同的逻辑分支,最终返回不同的结果。一个极端的现象是函数的参数过多,而且并不是每个参数都会为每

飞空静渡 1169

macOS Monterey官方镜像高速下载指南(附迅雷链接+兼容性清单)

本文提供macOS Monterey官方镜像的高速下载指南,重点介绍利用迅雷等工具加速下载官方安装包的有效方法。同时,详细列出了系统兼容性清单,帮助用户在下载前确认设备支持,并分享了从下载、验证到安全安装的完整流程与常见问题解决方案。

j7k8l的博客 2172

C++中的模板特性(Traits)

C++中的模板特性(Traits)是一种常见的技术,用于在编译时提取或操作类型信息。Traits类提供了一种灵活且可扩展的方法,用于实现类型特定的行为和元编程。

qq_41328432的博客 1096

用Python手把手教你实现一个多层感知机(MLP)——从理论到代码实战

本文详细介绍了如何使用Python和Theano库从零开始实现多层感知机(MLP),涵盖从核心原理到代码实战的全过程。通过构建隐藏层、输出层和完整MLP模型,结合权重初始化、激活函数选择和训练技巧,帮助开发者深入理解神经网络工作机制,并应用于实际机器学习任务。

web39explorer的博客 970

基于LLM的电商数据分析系统

随着电商行业的蓬勃发展,每天都会产生海量的数据,这些数据包含了用户的行为信息、商品信息、销售数据等。如何从这些繁杂的数据中提取有价值的信息,为电商企业的决策提供支持,成为了一个关键问题。基于LLM的电商数据分析系统的目的就是利用大语言模型强大的自然语言处理和数据分析能力,对电商数据进行深入挖掘和分析,帮助企业了解市场趋势、用户需求、商品销售情况等,从而制定更加合理的营销策略、优化商品库存管理、提升用户体验等。本系统的范围涵盖了电商领域的多个方面,包括用户行为分析、商品分析、销售数据分析等。

AI Python 编程之道的博客 808

C++模板之trait与模板技巧

一:trait 1.Fixed Traits 主要是构造适应各种类型的函数Fixed主要指,一旦定义了这个分离的 trait,则无法在算法中进行改写。value trait 是用于针对型别进行 value 方面的操作,如 zero(),它是 fixed trait 和下面的另外一种参数化萃取的一部分。 template class accumulation_traits; t

FreeeLinux's blog 2626

【定制功能】LVGL 页面管理

页面管理的主要针对实际复杂的UI项目的。支持多页面管理,包含页面跳转和返回(主要是方便项目功能管理)支持后台页面自动销毁、前台页面自动创建(主要是节约资源使用)支持语言切换逻辑(页面重建功能)支持主题切换逻辑支持页面切换动画效果首先,页面管理是针对act_src图层来讲的。仅在screens数组中供act_src切换的对象树才会被此页面管理功能所管理。这意味着,如果top_layer或者sys_layer图层上,有页面需要重建时,需要特殊处理(实际项目中top_layer或者。

Bigan(安)的博客 5751

c++ template(八)——trait模板与policy类

模板的神奇之处就在于我们可以针对多种类型对类和函数进行参数化,但有时候为了解决一些问题,我们需要引入较多的参数,这样就显得很麻烦?有什么好的解决方法呢? 这是有人会想,对一些额外的参数指定缺省值就行了啊,当然可以啊!但是过多的缺省值使我们的代码也会显的很麻烦,有时候可能会出现效率低下的问题。因此,我们引入了trait模板机制和policy类来解决这个问题。 policy类和trait模板机制,是...

风吟 625

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

C++模板技巧:Trait 搭配 enable_if 实现模板选择性实例化

我们偶然间聊到了这两个要素,于是心血来潮总结了一下。这篇文章需要一定的C++模板基础来阅读。

weixin_42445065的博客 664

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

我的C++实践(4):trait与policy模板技术

    我们知道,类有属性(即数据)和操作两个方面。同样模板也有自己的属性(特别是模板参数类型的一些具体特征,即trait)和算法策略(policy,即模板内部的操作逻辑)。模板是对有共性的各种类型进行参数化后的一种通用代码,但不同的具体类型又可能会有一些差异,比如不同的类型可能会有自己的不同特征和算法实现策略。trait模板和policy模板技术就是把模板的trait和policy这两个针对不同

Jack Zhou的专栏 5314

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

C++模板编程进阶:将Trait类模板作为模板参数实现编译期策略模式

在C++模板元编程中,模板参数通常用于传递类型或整型值,以实现代码的通用性和类型安全。其核心原理是通过编译期参数化,将算法与具体类型解耦,从而提升代码的复用性和灵活性。这项技术的核心价值在于支持编译期多态和策略模式,允许开发者在编译时注入不同的行为或策略,而无需修改核心算法逻辑。在实际应用场景中,它广泛用于构建高度可配置的库组件,如自定义分配器、序列化框架、迭代器适配器等,实现编译期的策略选择。本文聚焦于一种高级技巧:将完整的Trait类模板作为模板参数传递,这进一步深化了依赖倒置原则在编译期的应用,使得组

weixin_34122604的博客 313

C++模板元编程:将Trait类模板作为模板参数的设计与实践

在C++模板元编程中,Trait(特性萃取)是一种在编译期获取类型信息的核心机制,它通过提供统一的接口来抽象类型特性,实现泛型算法的通用性。其原理是利用类模板或模板特化,在编译时推导出类型的常量、嵌套类型或静态方法,从而消除对具体类型的依赖。这一技术的核心价值在于实现编译时的策略注入与彻底解耦,提升泛型组件的可复用性,支持多套并行的类型特性体系。在工程实践中,通过将Trait类模板作为模板参数传递,可以构建高度灵活、可配置的泛型组件,例如实现可插拔的序列化框架或策略化的算法骨架。这种模式特别适用于设计底层库

weixin_30902251的博客 371

(C++模板编程):将trait类模板用作模板参数

将trait类模板用作模板参数 【引例】 //SumFixedTraits类模板 template <typename T> struct SumFixedTraits; template<> struct SumFixedTraits<char> { using sumT = int; static sumT initValue() { return 0; } }; template<> struct SumFixedTraits<in

baidu_41388533的博客 350

C++模板:type_trait

C++模板:type_trait

_ 1925

C++ trait模板参数:编译期类型契约与泛型设计核心

trait 是 C++ 泛型编程中用于表达类型行为契约的编译期机制,其本质不是运行时配置,而是通过模板参数显式声明接口规范。它基于 SFINAE 和 if constexpr 实现静态多态,在 allocator_traits、iterator_traits 等标准设施中承担适配层与契约定义双重角色。技术价值在于解耦类型实现与使用逻辑,支持零开销抽象、跨标准兼容与策略组合。典型应用场景包括内存分配器适配、序列化后端切换、图形 API 统一抽象等。本文深入剖析 trait 作为模板参数的设计原理、工业级实践及

weixin_30889885的博客 519

C++ Type Trait

所谓Type trait提供一种用来处理type属性的办法。它是一个模板,可在编译器根据一或多个模板实参产出一个type或value 示例如下: 针对整数类型的弹性重载 假设有一个函数foo(),对于整数类型和浮点数类型的实参,它该有不同的实现。通常的做法是将它重载,使它拥有针对整数类型和针对浮点数类型两个版本: void foo(short); void foo(int); void foo(...

qq_44800780的博客 804

C++新经典模板与泛型编程:将trait类模板用作模板参数

在上面的代码中,引入了第2个类型模板参数U,该模板参数有一个默认值,而且这个默认值可以通过第1个模板参数推断出来(第2个模板参数依赖于第1个模板参数),所以一般不需要指定。但如果有特殊的需求,也是可以指定的,这就增加了。上面这两行代码,在调用funcsum()时,第1个类型模板参数T被推断为char类型,第2个类型模板参数U就变成了SumFixedTraits类型。函数模板用于计算数组元素的和值。也就是说,计算和值的时候,用于保存和值的。的第2个类型模板参数指定为一个完全不同的。中以往的代码行如下。

the growth of Nick 554

C++ 萃取技术——将萃取类模板用作模板参数

在 C++ 编程中,理解和应用 Trait 类模板是提高代码质量和灵活性的关键技术之一。Trait 类模板提供了一种机制,通过这种机制可以在编译时查询或设置有关类型的特定属性。这些属性可能包括类型的数学特性、行为特性、或者与类型相关的支持操作。

慢慢记录,慢慢更新。 1943
上一篇: 关于深度探索C++对象模型笔记
下一篇: 关于bayes错误率计算公式P[error] = P[error | x]P(x)dx
Savitch
博客等级 码龄16年 84粉丝 130原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值