ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

C++模板元编程面试必考:从入门到精通全解析

C++模板元编程面试必考:从入门到精通全解析 C++模板元编程面试必考:从入门到精通全解析本文是C++面试系列第8篇,专注模板元编程(Template Metaprogramming, TMP)。模板元编程是C++最强大的特性之一,也是大厂面试中的高频考点。掌握TMP不仅能让你在面试中脱颖而出,更能写出高性能的泛型代码。一、什么是模板元编程?模板元编程是一种在编译期执行计算的技术。与普通程序在运行时(runtime)执行不同,模板元程序的执行结果是编译期生成的代码。核心特点特性普通编程模板元编程执行时机运行时编译时图灵完备-是性能受运行时开销影响零运行时开销调试难度低高(错误信息复杂)适用场景通用泛型库、类型萃取、编译期计算经典入门:编译期阶乘#includeiostream// 模板元编程:编译期计算阶乘templateunsignedNstructFactorial{staticconstexprunsignedlonglongvalue=N*FactorialN-1::value;};// 特化:递归终止条件templatestructFactorial0{staticconstexprunsignedlonglongvalue=1;};intmain(){// 计算在编译期完成,运行时直接使用结果std::cout"10! = "Factorial10::valuestd::endl;// 输出: 10! = 3628800// 验证:这是编译期常量static_assert(Factorial10::value==3628800,"Factorial computation failed");// 可以用作数组大小(必须是编译期常量)intarr[Factorial5::value];// 大小为120的数组std::cout"Array size: "sizeof(arr)/sizeof(arr[0])std::endl;return0;}面试QA:编译器如何保证递归终止?模板特化(Specialization)提供了递归的终止条件。当编译器实例化Factorial0时,会匹配到全特化版本,递归停止。如果没有特化,编译器会无限递归直到达到实例化深度限制(通常900层左右)。二、SFINAE与类型萃取SFINAE(Substitution Failure Is Not An Error)是模板元编程的基石。当模板参数替换失败时,编译器不会报错,而是静默地丢弃该特化,尝试其他重载。2.1 std::enable_if 的原理// C++11 实现 enable_iftemplateboolB,typenameT=voidstructenable_if{};templatetypenameTstructenable_iftrue,T{usingtype=T;};// 使用示例:只对整数类型启用函数templatetypenameTtypenamestd::enable_ifstd::is_integralT::value,T::typesafe_divide(T a,T b){if(b==0)return0;returna/b;}// 对浮点类型启用另一个版本templatetypenameTtypenamestd::enable_ifstd::is_floating_pointT::value,T::typesafe_divide(T a,T b){if(std::abs(b)1e-9)returnstd::numeric_limitsT::infinity();returna/b;}intmain(){std::coutsafe_divide(10,3)std::endl;// 整数版本: 3std::coutsafe_divide(10.0,3.0)std::endl;// 浮点版本: 3.33333return0;}2.2 自定义类型萃取面试中经常要求手写类型萃取工具:#includetype_traits#includeiostream#includestring#includevector// 1. 判断是否是容器(有begin/end成员)templatetypenameT,typename=voidstructis_container:std::false_type{};templatetypenameTstructis_containerT,std::void_tdecltype(std::declvalT().begin()),decltype(std::declvalT().end()),decltype(std::declvalT().size()):std::true_type{};// 2. 判断是否有特定的成员函数templatetypenameT,typename=voidstructhas_to_string:std::false_type{};templatetypenameTstructhas_to_stringT,std::void_tdecltype(std::declvalT().to_string()):std::true_type{};// 3. 判断是否是智能指针templatetypenameTstructis_smart_pointer:std::false_type{};templatetypenameTstructis_smart_pointerstd::unique_ptrT:std::true_type{};templatetypenameTstructis_smart_pointerstd::shared_ptrT:std::true_type{};templatetypenameTstructis_smart_pointerstd::weak_ptrT:std::true_type{};// 测试structMyStruct{std::stringto_string()const{return"MyStruct";}};intmain(){std::coutstd::boolalpha;std::cout"vector is container: "is_containerstd::vectorint::valuestd::endl;// truestd::cout"int is container: "is_containerint::valuestd::endl;// falsestd::cout"MyStruct has to_string: "has_to_stringMyStruct::valuestd::endl;// truestd::cout"int has to_string: "has_to_stringint::valuestd::endl;// falsestd::cout"unique_ptr is smart: "is_smart_pointerstd::unique_ptrint::valuestd::endl
返回列表