江苏和城乡建设部网站首页,林和西网站建设,江阴百度推广公司,我的个人主页模板前言
让我们实现一个 IsAllTrue 函数#xff0c;支持变长参数#xff0c;可传入多个表达式#xff0c;必须全部计算为true#xff0c;该函数才返回true。
本文记录了逐步实现与优化该函数的思维链#xff0c;用到了以下现代C新特性知识#xff0c;适合对C进阶知识有一定…前言
让我们实现一个 IsAllTrue 函数支持变长参数可传入多个表达式必须全部计算为true该函数才返回true。
本文记录了逐步实现与优化该函数的思维链用到了以下现代C新特性知识适合对C进阶知识有一定了解的人。这样一种从实际问题来学习和运用知识的过程还是挺有趣的特此整理分享一下。
可变长参数模板 (C11)折叠表达式 (C17)条件编译 if constexpr (C17)类型萃取 type traits (C11)完美转发std::forward (C11)结构化绑定 std::bind (C11)
初级版本——基于初始化列表实现
可以使用初始化列表 std::initializer_list 存储多个bool变量实现传入多个bool值的目的这种方法实际上该函数只有一个参数实现如下
bool IsAllTrue(const std::initializer_listbool conditions) {return std::all_of(conditions.begin(), conditions.end(), [](const bool a) {return a;});
}使用方法如下
int a 1;
bool b true;
auto c []() {return true;}
IsAllTrue({a, b, c});这个方法的实现简单易用但是对于代码有更高追求的人并不满足于此以上实现存在如下问题
传入参数是一个初始化列表需要写大括号{}不够优雅。调用函数前计算了每一个条件表达式但实际任意一个为false即可返回可能存在如下问题 不必要的函数调用带来一定计算开销当前后表达式存在依赖关系时比如 p p →a 如果p是指针且为空 计算p→a 会导致程序崩溃。
对于不了解这个函数用法的人而言使用这个实现是会存在一定风险的。所以我们需要想办法利用 实现短路求值以及对函数结果的延迟计算。
进阶版本——基于折叠表达式实现
折叠表达式(Fold expressions) 折叠表达式是C17引入的新特性可通过二元操作符折叠可变长参数模板中的参数包。这个特性的引入是为了简化C11可变长参数模板的使用。
根据左右方向可分为左折叠和右折叠
一元左折叠Unary right fold和一元右折叠Unary left fold形式如下
( pack op... ) //一元右折叠从右往左计算 等同于(E1 op (... op (EN-1 op EN)))
( ... op pack ) //一元左折叠从左往右计算 等同于(((E1 op E2) op ...) op EN)在大多数情况下对于交换律成立的操作符如 和 *左折叠和右折叠的结果是相同的。然而对于非交换的操作符结果可能不同例如减法或除法。
根据是否有初始值可分为一元和二元
二元折叠表达式分为二元右折叠Binary right fold和 二元左折叠Binary left fold。
( pack op ... op init ) //二元右折叠
( init op ... op pack ) //二元左折叠使用二元左折叠的例子
templatetypename... Args
void printer(Args... args)
{((std::cout args ), ...) \n;
}基于一元右折叠的IsAllTrue函数
基于 运算符的一元右折叠(Unary right fold)实现IsAllTrue如下
templatetypename... Args
bool IsAllTrue(Args... args) { return (std::forwardArgs(args) ...);
}注折叠表达式的最外层括号是必须的。
但以上实现该模板本质上仍只能支持变长的多个bool参数这会导致先计算出bool值再传入仍未实现函数结果的延迟计算。
使用type traits 进一步优化
如何可以实现延迟计算呢首先我们可以明确下传递给该函数的参数类型可能是bool值、可以计算出bool值的表达式或可调用对象、可转换为bool值的指针和数值。
总体可分为两类一类是可转换为bool的表达式另一类是可计算出bool的可调用对象。
由于参数类型(bool、函数对象、指针等)和类型特征(是否可调用、是否可以转成bool)均是可以在编译期确定的。
为了避免在编译期把模板参数类型都推断为bool可定义 IsTrue 函数模板定义表达式bool值的计算方式使模板可以推断出原表达式自身的类型从而可以延迟其计算过程。其中用到了编译期条件if constexpr 和 一种类型萃取是否可调用 std::is_invocable_v 这两个均是C17引入的特性。
如果具备可调用的特征则进行函数调用并返回结果否则将其转换为bool值返回。实现如下 template typename T
bool IsTrue(T value) {if constexpr (std::is_invocable_vT) {// 如果是可调用对象调用它并返回结果return std::forwardT(value)();} else {// 否则将其转换为boolreturn static_castbool(std::forwardT(value));}
}基于以上模板改写 IsAllTure 模板函数
template typename... Args
bool IsAllTrue(Args... args) {return (IsTrue(std::forwardArgs(args)) ...);
}该实现的本质是我们希望在用N个表达式传入该模板函数后模板实例化为形同如下形式从而可以实现短路机制
static_castbool(Expr1) Expr2() static_castbool(Expr3) ... ExprN()函数测试
对以上代码进行如下测试注释为输出结果可以看到能够满足我们的需求
auto lambdaTrue []() { std::cout lambda truestd::endl;return true;
};
auto lambdaFalse []() { std::cout lambda falsestd::endl;return false;
};
class Foo {
public:int a;
};
Foo* p nullptr;
IsAllTrue(true, lambdaTrue); // 输出lambda true
IsAllTrue(false, lambdaTrue); // 无输出实现了短路机制以及延迟计算
IsAllTrue(p, p-a); // 正常运行不会coredump以上为了方便均使用定义了无参lambda函数进行了测试。为了延迟一般含参函数的计算结果能够方便传入带参数的函数对象还可以基于std::bind实现一个用于生成可调用对象的函数
template typename F, typename... Args
auto make_callable(F f, Args... args) {return std::bind(std::forwardF(f), std::forwardArgs(args)...);
}比如
bool less(int a, int b) {return a b;
}IsAllTrue(true, make_callable(less, 1, 2));完整测试代码https://compiler-explorer.com/z/fTvq7Y36Y
知识总结
本文使用了以下C知识实现了一个高效的IsAllTrue函数优点为它的使用安全且较为高效缺点在于代码实现较为复杂对C知识掌握程度要求较高过多使用也会导致代码体积膨胀。
条件编译if constexpr 这个关键字用于在编译时判断是否满足条件。如果 T 是可调用对象例如 lambda 或函数对象则调用它并返回结果。如果 T 不是可调用对象则将其转换为 bool。 类型萃取std::is_invocable_v 这是一个用于判断类型 T 是否可调用的特性。如果 T 是可调用对象则 std::is_invocable_vT 返回 true。需要包含 type_traits 头文件 完美转发 std::forward std::forwardT(value) 确保参数的完美转发保留其左值或右值性质。 可变长参数模板支持可变数量的参数包语法用 T ... args表示。折叠表达式 使用了C17中的折叠表达式 它会对参数从左到右进行求值。简化了可变长参数模板的使用提供了一种简洁而直观的方式来对参数包进行展开和操作从而避免了递归或显式循环的繁琐。 结构化绑定 std::bind 可绑定参数args到一个函数f并返回一个可调用对象。
参考
https://en.cppreference.com/w/cpp/language/fold 如果本文对您有帮助请点赞、关注
公众号七昂的技术之旅 文章转载自: http://www.morning.qcrhb.cn.gov.cn.qcrhb.cn http://www.morning.mtmph.cn.gov.cn.mtmph.cn http://www.morning.nzcys.cn.gov.cn.nzcys.cn http://www.morning.rpstb.cn.gov.cn.rpstb.cn http://www.morning.dbcw.cn.gov.cn.dbcw.cn http://www.morning.wjlnz.cn.gov.cn.wjlnz.cn http://www.morning.rtryr.cn.gov.cn.rtryr.cn http://www.morning.rttp.cn.gov.cn.rttp.cn http://www.morning.ctxt.cn.gov.cn.ctxt.cn http://www.morning.pzwfw.cn.gov.cn.pzwfw.cn http://www.morning.knjj.cn.gov.cn.knjj.cn http://www.morning.rkgyx.cn.gov.cn.rkgyx.cn http://www.morning.xnwjt.cn.gov.cn.xnwjt.cn http://www.morning.wxwall.com.gov.cn.wxwall.com http://www.morning.thntp.cn.gov.cn.thntp.cn http://www.morning.rykmz.cn.gov.cn.rykmz.cn http://www.morning.thwhn.cn.gov.cn.thwhn.cn http://www.morning.pbsfq.cn.gov.cn.pbsfq.cn http://www.morning.gpsrk.cn.gov.cn.gpsrk.cn http://www.morning.yhjrc.cn.gov.cn.yhjrc.cn http://www.morning.rlhjg.cn.gov.cn.rlhjg.cn http://www.morning.xnqjs.cn.gov.cn.xnqjs.cn http://www.morning.blzrj.cn.gov.cn.blzrj.cn http://www.morning.wkknm.cn.gov.cn.wkknm.cn http://www.morning.grjh.cn.gov.cn.grjh.cn http://www.morning.ndrzq.cn.gov.cn.ndrzq.cn http://www.morning.qdbcd.cn.gov.cn.qdbcd.cn http://www.morning.xgmf.cn.gov.cn.xgmf.cn http://www.morning.kryxk.cn.gov.cn.kryxk.cn http://www.morning.kxbdm.cn.gov.cn.kxbdm.cn http://www.morning.tldhq.cn.gov.cn.tldhq.cn http://www.morning.rwqj.cn.gov.cn.rwqj.cn http://www.morning.lgkbn.cn.gov.cn.lgkbn.cn http://www.morning.jcxzq.cn.gov.cn.jcxzq.cn http://www.morning.5-73.com.gov.cn.5-73.com http://www.morning.qrlkt.cn.gov.cn.qrlkt.cn http://www.morning.mttqp.cn.gov.cn.mttqp.cn http://www.morning.ptzf.cn.gov.cn.ptzf.cn http://www.morning.smmby.cn.gov.cn.smmby.cn http://www.morning.nsrlb.cn.gov.cn.nsrlb.cn http://www.morning.ydwnc.cn.gov.cn.ydwnc.cn http://www.morning.srtw.cn.gov.cn.srtw.cn http://www.morning.mqwdh.cn.gov.cn.mqwdh.cn http://www.morning.jzgxp.cn.gov.cn.jzgxp.cn http://www.morning.qkrqt.cn.gov.cn.qkrqt.cn http://www.morning.xkjrs.cn.gov.cn.xkjrs.cn http://www.morning.qlsyf.cn.gov.cn.qlsyf.cn http://www.morning.pflpb.cn.gov.cn.pflpb.cn http://www.morning.mgnrc.cn.gov.cn.mgnrc.cn http://www.morning.jybj.cn.gov.cn.jybj.cn http://www.morning.qmnjn.cn.gov.cn.qmnjn.cn http://www.morning.xfxlr.cn.gov.cn.xfxlr.cn http://www.morning.xhftj.cn.gov.cn.xhftj.cn http://www.morning.ptysj.cn.gov.cn.ptysj.cn http://www.morning.jlpdc.cn.gov.cn.jlpdc.cn http://www.morning.dnvhfh.cn.gov.cn.dnvhfh.cn http://www.morning.lzqnj.cn.gov.cn.lzqnj.cn http://www.morning.txfzt.cn.gov.cn.txfzt.cn http://www.morning.qtrlh.cn.gov.cn.qtrlh.cn http://www.morning.nbpqx.cn.gov.cn.nbpqx.cn http://www.morning.zhishizf.cn.gov.cn.zhishizf.cn http://www.morning.rhzzf.cn.gov.cn.rhzzf.cn http://www.morning.xjkfb.cn.gov.cn.xjkfb.cn http://www.morning.ljxxl.cn.gov.cn.ljxxl.cn http://www.morning.ypklb.cn.gov.cn.ypklb.cn http://www.morning.lynkz.cn.gov.cn.lynkz.cn http://www.morning.gyxwh.cn.gov.cn.gyxwh.cn http://www.morning.lbxhy.cn.gov.cn.lbxhy.cn http://www.morning.byshd.cn.gov.cn.byshd.cn http://www.morning.qzglh.cn.gov.cn.qzglh.cn http://www.morning.nwqyq.cn.gov.cn.nwqyq.cn http://www.morning.hbqfh.cn.gov.cn.hbqfh.cn http://www.morning.mlpch.cn.gov.cn.mlpch.cn http://www.morning.wlddq.cn.gov.cn.wlddq.cn http://www.morning.rqbr.cn.gov.cn.rqbr.cn http://www.morning.sbdqy.cn.gov.cn.sbdqy.cn http://www.morning.kpgms.cn.gov.cn.kpgms.cn http://www.morning.rhchr.cn.gov.cn.rhchr.cn http://www.morning.mzcsp.cn.gov.cn.mzcsp.cn http://www.morning.gwsll.cn.gov.cn.gwsll.cn