当前位置: 首页 > 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> 就不存在,就不能使用

相关文章:

  • 人工智能(AI)与机器学习(ML):定义、区别及应用解析
  • 互联网大厂Java求职面试:AI与大模型集成的云原生架构设计
  • 流程编辑器Bpmn与LogicFlow学习
  • C40-指针
  • nn.Module 与 nn.functional
  • Hashmap 和 map的区别
  • 单片机开发软件
  • mysql数据库-3 (主从复制)
  • Windows AD 域客户端电脑时间不准解决方案
  • 卷积神经网络和深度神经网络的区别是什么?
  • 地球阿米特黑客组织使用新型工具攻击军用无人机供应链
  • 常见三维引擎坐标轴 webgl threejs cesium blender unity ue 左手坐标系、右手坐标系、坐标轴方向
  • TypeScript:类
  • 达利欧:“交易的艺术”与“背后的力量”
  • 了解光学影像
  • C#自定义控件-实现了一个支持平移、缩放、双击重置的图像显示控件
  • OpenCV人脸识别EigenFace算法、案例解析
  • MySQL 开发的智能助手:通义灵码在 IntelliJ IDEA 中的应用
  • 自营交易考试为何出圈?一场模拟交易背后的真实竞争
  • 为什么elasticsearch配置文件JVM配置31G最佳
  • 商务部召开全国离境退税工作推进会:提高退税商店覆盖面,扩大入境消费
  • 巴基斯坦与印度停火延长至18日
  • 国家卫生健康委通报关于肖某引发舆情事件调查处置进展情况
  • 通用汽车回应进口车业务调整传闻:因经济形势变化重组,致力于在中国持续发展
  • 30平米的无障碍酒吧里,我们将偏见折叠又摊开
  • 网约车座椅靠背张贴“差评者得癌症”,如祺出行:未收到投诉无法处理