C++模板元编程详细教程(之八)

文章探讨了C++模板元编程中如何在运行期通过动态索引获取元组元素,分析了std::get的静态特性以及为何STL不提供动态get。通过示例展示了如何利用模板元编程的编译期展开技术,实现在已知元组类型的情况下,根据运行期数据调用元素的方法。此外,还介绍了如何生成序列并应用到元组展开,以实现用元组调用函数的功能。

前序文章请看:
C++模板元编程详细教程(之一)
C++模板元编程详细教程(之二)
C++模板元编程详细教程(之三)
C++模板元编程详细教程(之四)
C++模板元编程详细教程(之五)
C++模板元编程详细教程(之六)
C++模板元编程详细教程(之七)

实现一个动态的get

如果读者对元组工具,也就是std::tuple很熟悉的话,那么对std::get也一定不陌生。我们可以通过std::get<N>(tu)的方式把原组的第N个元素取出来。

但是,不知道大家有没有思考过这样一个问题,std::get是静态模板工具,所以参数N必须要编译期确定。那为什么STL不提供一个动态序号获取元组元素的能力呢?也就是说类似tu.get(n),其中n是函数参数(运行期数据)。最主要的原因就在于类型不确定,假如说我们真的要给tuple提供一个get方法,那么方法的返回值是不确定的,于是这就成了一个RTTI(Run-Time Type Identification)方法。而STL是模板库,并不提供任何RTTI行为,自然也就不会提供类似的方法。

但假如,我们在实际开发中,针对某个元组,可以确定(或可以正确处理)它的类型,在这种情况下希望可以提供一个动态的get工具应当如何来做?举例来说:

class Base {
   
   
 public:
  virtual void f() const = 0;
};

class Ch1 : public Base {
   
   
 public:
  void f() const override {
   
   }
};

class Ch2 : public Base {
   
   
 public:
  void f() const override {
   
   }
};

// 利用多态调用f方法
template <typename... Args>
std::enable_if_t<
	std::conjunction_v<
			std::is_base_of<Base, Args>...
	>, void> 
InvokeF(const std::tuple<Args...> &tup, size_t index) {
   
   
  // 考虑这里应该怎么写
}

void Demo() {
   
   
  // 一个元组,里面都是Base的子类对象
  std::tuple tu{
   
   Ch1{
   
   }, Ch2{
   
   }, Ch1{
   
   }};
  InvokeF(tu, 1); // 调用Ch2的f方法,注意这个参数1是运行期数据
}

解释一下上面例程,Ch1Ch2都是Base类的子类,InvokeF函数是传入一个元组tup和一个序号index,我们要把tup的第index个元素拿出来,去调用它的f方法,这里要求tup的元素都必须是Base的子类。

现在问题就在于,index是一个运行期数据,我们用std::get<index>肯定是不可以的,那怎么办?只能采用编译期展开的方式。

具体来说就是,由于我们这里的元组类型是编译期确定的,那么对应的变参数量也就是确定的(比如上面例程中就是3个),那么,我们就在编译期生成分别应对假如index就是这种情况,应当怎么去做。

以上面例程为例,由于编译期不知道index可能是几,但针对std::tuple<Ch1, Ch2, Ch1>这种类型的元组来说,index只能是012这3种情况时才可以有合法处理。所以,我们就分别写出当index012时,应当做的处理。这个就叫做「编译期展开」,也就是在编译期枚举出运行时可能传入的所有数据,分别生成对应的代码指令,然后当运行期数据确定的时候去执行对应的指令。

如果手动来写,就应该写成:

template <typename... Args>
void InvokeF_0(const std::tuple<Args...> &tu) {
   
   
  std::get<0>(tu).f();
}

template <typename... Args>
void InvokeF_1(const std::tuple<Args...> &tu) {
   
   
  std::get<1>
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

borehole打洞哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值