当前位置: 首页 > news >正文

在C++模板中,设置一个无名模板参数的默认值为0到底是什么含义

看下面的例子

#include<type_traits>
// define a class template, and the template parameter is a value of bool。by default,this class is empty, doesn't define any member
template<bool Condition>
struct lfEnableIf
{ };
// specialize the above class template, only when the value is true, the class has a defined type member--Type
template<>
struct lfEnableIf<true>
{typedef int Type;
};// define a class template which has a static constant value, true/false
template<bool Val>
struct lfBoolConstant
{static const bool Value = Val;    
};//定义两个特化后的模板类,其中一个具有静态常量 value=true, 另一个具有静态常量value=false
typedef lfBoolConstant<true> lfTrueType;
typedef lfBoolConstant<false> lfFalseType;//定义一个模板类lfIsArithmetic,默认含有一个静态常量value=false
template <typename NumT> struct lfIsArithmetic : lfFalseType{};// 特化上面的模板类,使其在参数类型为char,bool,float时,特化模板类含有一个静态常量value=true
template <> struct lfIsArithmetic<char> : lfTrueType{};
template <> struct lfIsArithmetic<bool> : lfTrueType{};
template <> struct lfIsArithmetic<float> : lfTrueType{};// 最后的应用,使用上述定义的各个模板类,定义一个新的模板类,这个新的模板类含有两个模板参数,其中第一个是个类型参数,第二个是个数值型参数
template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0>  // v or no v is same,nameless parameter SFINAE
struct Test
{static void print(){std::cout << "参数类型为:" <<typeid(T).name()<< std::endl;}};int main()
{Test<float>::print();// template<float, float = 0> struct Test;Test<bool>::print();// template<bool, bool = 0> struct Test;Test<char>::print();// template<char, char = 0> struct Test;// Test<int>::print();       // error, as fEnableIf<lfIsArithmetic<int>::Value>::Type doesn't exist at allreturn 0;
}

执行结果为:

让我们来看这一行,template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0> struct Test的第二个模板参数,设置一个无名的模板参数的默认值为0到底是什么含义?

这一行其实定义一个有名的模板类型参数T和一个无名的模板数值型参数lfEnableIf<lfIsArithmetic<T>::Value>::Type,这第二个参数等价于template<int n=0> struct S{};

在lfEnableIf条件满足(lfIsArithmetic<T>::Value=true)的情况下,类型 lfEnableIf<lfIsArithmetic<T>::Value>::Type最终会被解析为类型int,于是上述那一堆就等价于

template<float, int = 0> struct Test;

template<bool, int = 0> struct Test;

template<char, int = 0> struct Test;

由于第二个模板参数的类型是一个在lfEnableIf范围内定义的一个内嵌类型,因此前面必须有typename 来告诉编译器,lfEnableIf<lfIsArithmetic<T>::Value>::Type是一个类型,而不是一个其它什么东西(比如不是类中的静态变量什么的)。同时这第二个模板参数是无名的,但是你可以给这个参数定义任何名字,这不会改变任何东西。比如template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type V = 0>

在上面的例子中,我给了这个无名参数一个名字V,这个参数名字在模板中任何地方都没有使用到,这正是我们没必要给一个确切名字的原因。这是一个虚参数,这也正是我们可以给这个虚参数赋予任何值的原因。我们可以设置默认值为0,也可以设置为42,这不会改变任何事情

于是在这种情况下,这两个关键字typename 就会带来一个误导:那就是你的这个模板中的第一个和第二个typename是类似的,其实不然,这两个typename 其实发挥的作用是完全不同的。第一个参数中的typename表示我定义一个模板参数类型T,这种情况下,typename 可以被class代替。而第二个typename, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0,则发挥一个不同的作用。typename仅仅用来告知编译器它后面的表达式是一个类型, 于是第二个参数就成为一个数值型模板参数(因为数值型模板参数不需要typename),这种情况下,typename不能被class替换

那么这个无名的模板参数默认值为0到底如何使用呢?那就是使用SFINAE原则,看typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0能否被正确解析,如果能被正确解析,那么Test结构就存在,Test结构就可以被使用。

比如T使用char时,lfIsArithmetic<char>就含有value=true的成员变量。于是lfEnableIf<true>就含有一个int型的类型Type,于是typename lfEnableIf<lfIsArithmetic<T>::Value>::Type就等价为int,于是Test<char> 就存在,接可以被使用。

如果T为int时,由于lfIsArithmetic<int>只含有value=false的成员变量,于是lfEnableIf<fasle>就不会定义type成员变量,于是解析lfEnableIf<lfIsArithmetic<T>::Value>::Type就报错,于是Test<int> 就不存在,就不能使用

http://www.xdnf.cn/news/463753.html

相关文章:

  • repmgr集群故障修复
  • 基于DWT的音频水印算法
  • 2025长三角杯数学建模B题教学思路分析:空气源热泵供暖的温度预测
  • Java转Go日记(三十六):简单的分布式
  • 【PmHub后端篇】PmHub中Seata分布式事务保障任务审批状态一致性
  • 【油藏地球物理正演软件ColchisFM】基于数据驱动的油藏参数叠前地震反演研究进展
  • Scrapy框架下地图爬虫的进度监控与优化策略
  • 智能化招标采购新基建:基于DeepSeek大模型+RAG技术的智能知识服务中枢
  • MinerU安装(pdf转markdown、json)
  • uniapp在APP上如何使用websocket--详解
  • 每日算法刷题计划Day7 5.15:leetcode滑动窗口4道题,用时1h
  • 《数字藏品社交化破局:React Native与Flutter的创新实践指南》
  • 游戏引擎学习第283天:“让‘Standing-on’成为一个更严谨的概念
  • 进程替换讲解
  • uniapp微信小程序一键授权登录
  • 牛客网NC218480统计正负数个数
  • SiFli-SDK 编译
  • 【Ubuntu】安装BitComet种子下载器
  • 语音识别-3,添加ai问答
  • IT系统的基础设施:流量治理、服务治理、资源治理,还有数据治理。
  • 工作实战之关于数据库表的备份
  • 『已解决』Python virtualenv_ error_ unrecognized arguments_--wheel-bundle
  • 浏览器验证证书
  • 【AI News | 20250515】每日AI进展
  • 蓝牙BLE协议之——LL层
  • 【LeetCode 热题 100】56. 合并区间 —— 一文弄懂排序+遍历经典解法(附Python代码)
  • 使用Mathematica绘制Clifford奇异吸引子
  • 香港科技大学广州|智能制造学域硕博招生宣讲会-西北工业大学
  • Windows AD 域客户端电脑时间不准解决方案
  • 解决xxx.jar中没有主清单属性的问题