首页 > 其他分享 >范围适配器的编译时大小

范围适配器的编译时大小

时间:2023-11-03 14:45:15浏览次数:28  
标签:std constant constexpr 适配器 rng 编译 大小 tc size

与标准不同,think-cell 的范围库已经原生支持编译时大小,因此我渴望尝试那里的习惯用法,看看它在实践中的效果如何。

 
namespace tc {
	template <typename Rng>
	constexpr auto size(Rng&& rng); // runtime-size of a range, like std::ranges::size
	
	template <typename Rng> requires tc::has_constexpr_size<Rng>
	constexpr auto constexpr_size = …; // compile-time size of a range given its type
}
tc::sizetc::constexpr_size

我们有两种方法来查询大小:一种size返回整数(如 )的函数std::ranges::size,以及一种constexpr_size变量模板,用于确定给定范围类型的编译时大小。在后一种情况下,我们可以通过创建类型constexpr_size的变量模板来直接应用该习惯用法std::integral_constant。这样用户就可以在界面中拥有充分的灵活性:

 
template <typename Rng>
void foo(Rng&& rng) {
	std::size_t runtime_size = tc::size(rng);
	constexpr std::size_t compile_time_size = tc::constexpr_size<Rng>();
	constexpr std::integral_constant compile_time_size_constant = tc::constexpr_size<Rng>;
}
tc::size和的接口tc::constexpr_size

剩下的就是tc::constexpr_size. 现状是使用特质专业化。请注意,还提供tc::constexpr_size自动支持的实现。tc::size

 
template <typename Rng>
struct constexpr_size_impl; // no definition

template <typename Rng>
constexpr auto constexpr_size = constexpr_size_impl<std::remove_cvref_t<Rng>>{};

// Real implementation delegates all tuple-like types to std::tuple_size, omitted here.
template <typename T, std::size_t N>
struct constexpr_size_impl<std::array<T, N>> : std::integral_constant<std::size_t, N> {};

// more specializations
之前的实施tc::constexpr_size

我们可以static constexpr std::integral_constant在实施中使用吗?

我想改变它以某种方式利用这个static constexpr std::integral_constant习语。也就是说,检查作为默认实现的tc::constexpr_size格式良好性的实现。Rng::size然后,我们只需要特征特化来为我们无法控制的类型提供实现,例如std::array. 虽然它对于尺寸总是已知的范围工厂非常有效,例如std::arraytc::empty_rangetc::all_values<Enum>,但它不适用于范围适配器。

考虑tc::transform_adaptor(our std::ranges::transform_view),它返回一个范围,其元素是通过应用函数转换的基础范围元素。至关重要的是,它不会更改范围的大小:如果基础范围rngN元素,tc::transform(rng, fn)则也有N元素。因此我们希望透明地转发大小属性rng

  • 如果rng具有constexpr大小(即tc::constexpr_size<Rng>格式良好),则 也应如此tc::transform(rng, fn)
  • 否则,如果rng具有运行时大小(即tc::size(rng)格式良好),则应该如此tc::transform(rng, fn)
  • 否则,它既没有constexpr也没有运行时大小。

static constexpr std::integral_constant使用for 的天真的尝试tc::constexpr_size可能如下所示:

 
template <typename Rng, typename Fn>
struct transform_adaptor {
	// for tc::constexpr_size and tc::size
	static constexpr std::integral_constant size = tc::constexpr_size<Rng>; // somehow constrained

	// for tc::size
	constexpr std::size_t size() const
		requires tc::has_size<Rng> && (!tc::has_constexpr_size<Rng>)
	{
		return tc::size(base_rng());
	}
};
天真的尝试

这里的问题是“某种程度上受到约束”的注释:与static函数不同,成员变量不能受到约束,也不能用成员函数重载。constexpr因此,只有在Rng有大小的情况下,我们才必须有条件地继承大小constexpr,这很丑陋。

我们也没有从使用中得到任何好处static constexpr std::integral_constant——用户不应该直接调用rng.size(),他们应该使用tc::sizeortc::constexpr_size来代替。static constexpr std::integral_constant所以在实现中使用没有任何好处。

有条件返回std::integral_constant.size()

因此,我们只有一个size()函数返回std::size_tor ,即范围大小的std::integral_constant“最”版本。constexpr这种方法继续适用于范围工厂,但现在我们也可以编写我们的适配器:

 
template <typename Rng, typename Fn>
struct transform_adaptor {
	// for tc::size and tc::constexpr_size
	constexpr auto size() const& requires tc::has_size<Rng> {
		if constexpr (tc::has_constexpr_size<Rng>)
			return tc::constexpr_size<Rng>;
		else
			return tc::size(base_rng());
	}
};
更好的实施

相应的特化tc::constexpr_size调用里面的函数decltype来得到结果:

 
// Rng has a size function that returns an integral_constant.
template <typename Rng> requires requires { decltype(std::declval<Rng&>().size())::value; }
struct constexpr_size_impl<Rng> : decltype(std::declval<Rng&>().size()) {};
tc::constexpr_size专业。

运行时版本tc::size不需要更改,因为范围仍然有一个.size()返回大小的成员函数,只需在返回类型本身中进行编码即可。

避免代码重复

虽然该方法很好,但存在一些代码重复。对于更复杂的范围(例如 ),这一点尤其明显tc::concat_adaptor,其大小是所有子范围大小的总和:

 
template <typename ... Rng>
struct concat_adaptor {
	constexpr auto size() const
		requires (tc::has_size<Rng> && ...)
	{
		if constexpr ((tc::has_constexpr_size<Rng> && ...))
			return std::integral_constant<std::size_t, (tc::constexpr_size<Rng>() + ...)>{};
		else
			return std::apply([](auto const& ... base_rng) {
				return (tc::size(base_rng) + ...);
			}, base_rng_tuple);
	}
};
size()为了tc::concat_adaptor

我们计算相同的值两次:一次作为 a std::integral_constant,一次作为std::size_t。我们可以通过使用辅助函数分割大小计算和结果包装来统一它:

 
template <auto Fn, typename ... Rng>
constexpr auto compute_range_adaptor_size(Rng&&... rng) {
	if constexpr ((tc::has_constexpr_size<Rng> && ...)) {
		auto constexpr value = Fn(tc::constexpr_size<Rng>()...);
		return std::integral_constant<std::size_t, value>{};
	} else {
		auto const value = Fn(tc::size(std::forward<Rng>(rng))...);
		return value;
	}
}

template <typename ... Rng>
struct concat_adaptor {
	constexpr auto size() const
		requires (tc::has_size<Rng> && ...)
	{
		return std::apply([](auto const& ... base_rng) {
			return tc::compute_range_adaptor_size<[](auto const ... n) {
				return (n + ...);
			}>(base_rng...);
		}, base_rng_tuple);
	}
};
size()用于tc::concat_adaptor使用tc::compute_range_adaptor_size()助手

辅助函数compute_range_adaptor_size()获取所有子范围并计算constexpr其大小的最大版本。然后将其传递给 lambda 来计算派生大小,并以大多数constexpr方式返回。请注意,lambda 必须作为非类型模板参数传递,因此我们可以在上下文中使用其结果constexpr

concat_adaptor::size()然后只需要compute_range_adaptor_size()使用适当的 lambda 和子范围进行调用,它就会自动工作。

结论

范围适配器的大小可以在编译时或运行时获得。std::integral_constant我们可以通过尽可能返回constexpr尺寸的最新版本来轻松转发该信息。

该模式可以应用于更多情况。例如,我最近添加了对tc::filter返回std::true_typeor的谓词的支持std::false_type。这样,我们就可以std::tuple使用与按值过滤运行时范围相同的机制按类型进行过滤。

https://www.think-cell.net.cn/

标签:std,constant,constexpr,适配器,rng,编译,大小,tc,size
From: https://www.cnblogs.com/SmartBear360/p/17807559.html

相关文章

  • 直播软件搭建,当前时间、既定时间后的时间及时间比较大小
    直播软件搭建,当前时间、既定时间后的时间及时间比较大小获取当前时间 //时间格式SimpleDateFormatdf=newSimpleDateFormat(“yyyy-MM-dd”);//现在的时间Datenow=newDate();//计算某一月份的最大天数Calendarcal=Calendar.getInstance();//Date转化为Calendarc......
  • 如何使用python 绘制圈圈大小相同的韦恩图
    百度之换数据,画之,就这么简单哦,如果要画大小一致的圈圈,只需要venn3.py里350代码改成如下即可:#areas=compute_venn3_areas(subsets,normalize_to)areas=compute_venn3_areas((1,1,1,1,1,1,1),normalize_to)importmatplotlib.pyplotaspltfrommatplotlib_vennimpor......
  • 预编译语句Prepared Statements,俗称动态sql
    --创建临时表用动态sql创建set@sqls=concat('createtemporarytable',`temptableTableName`,'(variablevarchar(200),variableValuevarchar(200),variableDatevarchar(50))');preparestmt1from@sqls;#准备好sql语句executestmt1;......
  • windows10编译scrcpy
    一、概述简介:Scrcpy是一款小巧的Android投屏软件,能够跨平台其支持Windows、Mac、Linux系统。右PC充当客户端,Android板子作为服务端。原理:Android将录屏发送给PC,PC接收到数据后进行展示。PC上鼠标点击录屏上对应的坐标,把坐标通过Socket通信传递给Android端,实现对Android......
  • VMWare虚拟机-修改界面大小(麒麟系统)
    一、下载linux.iso1.下载地址:http://softwareupdate.vmware.com/cds/vmw-desktop/ws/15.5.1/15018445/windows/packages/2.解压后,VMWare添加镜像iso,然后重启虚拟机 3.找到VMwareTools-10.3.10-13959562.tar.gz压缩包并解压         4.执行文件lssudo......
  • 倾斜摄影三维模型的根节点合并的文件大小与质量关系分析
    倾斜摄影三维模型的根节点合并的文件大小与质量关系分析 倾斜摄影三维模型的根节点合并过程涉及大量的数据,包括高分辨率图像和点云信息。在进行根节点合并时,文件大小和质量之间存在一定的关系。本文将分析倾斜摄影三维模型的根节点合并的文件大小与质量之间的关系。首先,文件......
  • zabbix安装完成后查看编译参数
    最近学习zabbix分布式监控系统,突然想如何查看自己编译时的参数,最终找到自己想要的结果。 1.首先进入zabbix源码目录2.用ls-l命令查看是否有一个叫config.log文件3.这个文件里面有当时编译安装的所选择的参数,但是。。。这个日志里面有上万行,怎么办呢4.这时就可以用到我......
  • nginx coturn socat privoxy opencv 静态编译
    文档说明:只记录关键的地方;发文时间:2023-11-02意义:linux环境,免安装下载后即可使用环境:alpine:3.18dockerclang状态:完善中体验编译结果nginx静态编译关键点nginxusePCRE2libraryonnginx1.21.5hg脚本全称是mercurialopensslzlibpcpre2等静态库......
  • Qt - 获得当前窗口所在屏幕的大小
    qt获得当前窗口所在屏幕的大小 假如这个窗口的指针为this,记得要加头文件哦#include<QDesktopWidget>#include<QApplication>//获得当前屏幕是第几屏幕intnumber=QApplication::desktop()->screenNumber(this);//如果number是-1会出现崩溃,就是用默认0if(number<0)......
  • qt按键图标大小和设置大小不符的问题记录
    问题描述:在导航栏中有几个toolbuttoon,ui文件设置的控件大小相同但图标大小不同问题解决:经过排查,图片和ui文件没有问题,最后发现qss样式中border-image,background-image和image对于相同图标会显示出不同大小。#background-image只根据图片资源的大小,不按照控件的大小,相对于控......