首页 > 编程语言 >C++模板编程-enable_if

C++模板编程-enable_if

时间:2024-05-16 15:40:42浏览次数:23  
标签:std enable 函数 C++ 编译器 funceb 模板

std::enable_if的使用

对于重载的函数或者函数模板的选择上,编译器内部有一个自己的规则,并不是简单粗暴的对函数就优先选择,对函数模板就靠后选择

替换失败并不是一个错误(SFINAE):Substitution Failure Is Not An Error,SFINAE看成是C++语言的一种特性或者说一种模板设计中要遵循的重要原则

针对函数模板而言,当用一个具体类型替换函数模板的参数时,可能会产生意想不到的问题:,比如产生一些毫无意义甚至是看起来语法上有错误的代码,对于这些代码,编译器并不一定报错,有可能是忽略。编译器认为这个函数模板不匹配针对本次的函数调用,就当这个函数不存在一样。转而去选择其他更匹配的函数或者函数模板

基础认识:C++11新标准中引入的类模板(结构模板。使用体现了C++编译器的SFINAE特性)

定位为一个helper模板(助手模板),用于辅助其他模板的设计,表现一种:编译器的分支逻辑(编译器就可以确定走哪条分支)

namespace nmsp1 {
    template<typename T>
    struct MEB
    {
        using type = T;
    };
}
>查看下enable_id的源码
nmsp1::MEB<int>::type abc = 1;  //就代表int类型

怎么理解这个篇特化版本:只有这个偏特化版本存在,才存在一个名字叫做type的类型别名(类型)

偏特化完全可以理解为一种编译器的条件分支语句

 

 

std::enable_if<true>::type* mypoint1 = nullptr;
//第二个有默认值,所以第二个采用void,那么type就是void

std::enable_if<false>::type* mypoint1 = nullptr;
//走的是泛化版本,false没有type这个别名

范例:enable_if用于函数模板中,典型应用是作为函数模板的返回类型

template<typename T>
typename std::enable_if<(sizeof(T) > 2)>::type funceb()
{
    //....
}

nmsp2::funceb<int>();//void funceb(){}
nmsp2::funceb<char>();//error:未找到匹配的重载函数,条件不满足

//C++14出了这个等同上面
template<typename T>
std::enable_if_t<(sizeof(T) > 2),T> funceb()
{
    T myt = {};
    return myt;
}

nmsp2::funceb<int>();//int funceb(){}
//nmsp2::funceb<char>();

如果是第一条语句:如果funceb函数模板中涉及到enable_if_t中的条件成立的时候,这个funceb代表是一个类型,如果是第二条,条件不成立,那么有SFINAE的特性存在,请编译器忽略我这个funceb的这个函数模板吧。那么对第二条语句上例的funceb这个函数模板是不存在那样

 

enable_if_t源码,别名模板

 

示例:用于类模板中

万能引用

namespace nmsp3 {
    class Human {
    public:

        //构造函数模板
        template<typename T>
        Human(T&& tmpname) :m_sname(std::forward<T>(tmpname))
        {
            cout << "Human(T&& tmpname)执行" << endl;
        }

        //拷贝构造函数
        Human(const Human& th) :m_sname(th.m_sname)
        {
            cout << "Human(const Human& th)拷贝构造函数模板执行" << endl;
        }

        //移动构造函数
        Human(Human&& th) :m_sname(std::move(th.m_sname))
        {
            cout << "Human(Human&& th)移动构造函数执行了" << endl;
        }

    private:
        string m_sname;
    };
}

string sname = "zhangshan";
nmsp3::Human myhuman(sname);
// nmsp3::Human myhuman3(myhuman);//实际编译器调用构造函数模板,而不是拷贝构造函数

代码解决,针对构造函数,如果给进来的参数是一个string类型的参数,就让这个构造函数模板生效,否则就让这个构造函数模板被忽略即可,也就是说,如果使用enable_if于构造函数模板中,enable_if的条件只需要设置成"形参类型==string

std::is_convertible,C++11引入的,两个模板参数分别是From 和 To:用于判断能否从某个类型隐式的准换到另外一个类型,返回是布尔值

cout << "string=>float: " << std::is_convertible<string, float>::value << endl; //string=>float: 0

cout << "float>=int: " << std::is_convertible<float, int>::value << endl;   //float>=int:  1

 解决方案

namespace nmsp4 {
    //别名模板
    template<typename T>
    using StrProcType = std::enable_if_t<std::is_convertible<T, std::string>::value>;

    class Human {
    public:

        //构造函数模板
        template<
            typename T,
            typename = std::enable_if_t<std::is_convertible<T,std::string>::value>
            //如果T能够成功转换成std::string类型,那么typename = void
            //typename = StrProcType<T>
        >
        Human(T&& tmpname) :m_sname(std::forward<T>(tmpname))
        {
            cout << "Human(T&& tmpname)执行" << endl;
        }

        //拷贝构造函数
        Human(const Human& th) :m_sname(th.m_sname)
        {
            cout << "Human(const Human& th)拷贝构造函数模板执行" << endl;
        }

        //移动构造函数
        Human(Human&& th) :m_sname(std::move(th.m_sname))
        {
            cout << "Human(Human&& th)移动构造函数执行了" << endl;
        }

    private:
        string m_sname;
    };
}


string sname = "zhangshan";
nmsp4::Human myhuman(sname);
nmsp4::Human myhuman3(myhuman);//成功调用拷贝函数
 private:
        string m_sname;
    };
}


string sname = "zhangshan";
nmsp4::Human myhuman(sname);
nmsp4::Human myhuman3(myhuman);//成功调用拷贝函数

https://blog.csdn.net/baidu_41388533/article/details/109689556

https://blog.csdn.net/baidu_41388533/article/details/109702574

标签:std,enable,函数,C++,编译器,funceb,模板
From: https://www.cnblogs.com/bwbfight/p/18196068

相关文章

  • 深度解读《深度探索C++对象模型》之C++虚函数实现分析(三)
    “深度解读《深度探索C++对象模型》”系列已经在CSDN上和我的公众号上更新完毕,请有需要的同学移步到我的CSDN主页里去阅读,主页地址:https://blog.csdn.net/iShare_Carlos?spm=1010.2135.3001.5421或者敬请关注我的公众号:iShare爱分享前面两篇请从这里阅读:深度解读《深度探索C+......
  • ansible自定义模板部署apache服务
    使用Ansible来部署Apache服务是一个很好的选择,因为它可以自动化部署过程,确保所有的服务器上都有相同的配置。以下是一个简单的步骤指南,展示如何使用Ansible来部署Apache服务:1创建角色目录首先,在/etc/ansible/roles下创建apache目录:mkdir-p/etc/ansible/roles/apache2......
  • 《Effective C++》第三版-5. 实现(Implementations)
    目录条款26:尽可能延后变量定义式的出现时间(Postponevariabledefinitionsaslongaspossible)条款27:尽量少做转型动作(Minimizecasting)条款28:避免返回handles指向对象内部成分(Avoidreturning“handles”toobjectinternals)条款29:为“异常安全”而努力是值得的(Striveforexc......
  • Ubuntu 24.04 LTS x86_64 OVF (sysin) - VMware 虚拟机模板
    Ubuntu24.04LTSx86_64OVF(sysin)-VMware虚拟机模板Ubuntu24.04LTS(GNU/Linux6.8.0-31-genericx86_64)请访问原文链接:Ubuntu24.04LTSx86_64OVF(sysin)-VMware虚拟机模板,查看最新版。原创作品,转载请保留出处。作者主页:sysin.orgUbuntu24.04LTS(GNU/Li......
  • Rocky Linux 9.3 x86_64 OVF (sysin) - VMware 虚拟机模板
    RockyLinux9.3x86_64OVF(sysin)-VMware虚拟机模板以社区方式驱动的企业Linux,RHEL100%1:1兼容免费发行版请访问原文链接:RockyLinux9x86_64OVF(sysin)-VMware虚拟机模板,查看最新版。原创作品,转载请保留出处。作者主页:sysin.orgRockyLinux9.3(5.14.0-36......
  • C++:自定义异常
    #include<iostream>#include<stdexcept>//自定义异常类classMyException:publicstd::exception{public://重写what()函数以提供异常的描述,const表示函数不会改变类的成员变量,noexcept表示不会抛出异常constchar*what()constnoexceptoverride{......
  • C++ 对象池
    对象池概念对象池模式(ObjectPoolPattern),是创建型设计模式的一种,将对象预先创建并初始化后放入对象池中,对象提供者就能利用已有的对象来处理请求,减少频繁创建对象所占用的内存空间和初始化时间。对象池的用户可以从池子中取得对象,对其进行操作处理,并在不需要时归还给池子而非......
  • C++基础篇
    输入输出流iostream向流写入数据<<运算符<<运算符接受两个运算对象,此运算符将给定的值写到给定的ostream对象中:左侧:运算对象为ostream对象,如cout、cerr、clog右侧:运算对象是要打印的值输出结果:写入给定值的那个ostream对象,即此运算符返回其左侧的运算对象。表达式等价于:(std......
  • P3366 【模板】最小生成树
    链接:https://www.luogu.com.cn/problem/P3366模板题:kruskal代码:核心是对边的排序,遍历,选择。#include<iostream>#include<vector>#include<algorithm>#include<math.h>#include<sstream>#include<string>#include<string.h>#include<......
  • 【django学习-28】列表界面模板下载与上传文件
    前言,我们在实际项目开发过程中,经常有列表界面,有上传功能,并且支持先下载模板,后上传1.实现效果与前端展示<formmethod="post"enctype="multipart/form-data"action="/depart/multi/">{%csrf_token%}<divclass="form-group"><inputtyp......