cub中的ChainedPolicy

目的

当我们要根据不同机器使用不同的超参数时候,可以使用下面模板编程实现

base

英伟达有很多显卡,显卡架构各有不同,但是如果写一个kernel给英伟达公司,就需要针对每一个架构写一套函数,如下:

kernel_35();
kernel_52();
kernel_75();
kernel_80();

但是很多时候英伟达各个架构显卡基础逻辑都兼容,但是为了不同的性能会配置不同的超参数:

struct Arch_35
{
	static constexpr int M = 35;
	static constexpr int N = 35;
}

struct Arch_52
{
	static constexpr int M = 52;
	static constexpr int N = 52;
}

template<typename ARCH>
kernel()
{
	int res = ARCH::M * ARCH::N;
};
// 正常使用,根据机器型号k选择对应的配置参数。
kernel<Arch_k>

你一个框架总不能让用户自己去指定吧(白嫖党要求真高),所以用户应该是无感知,使用方式如下:

kernel<ARCH_auto>();

如下实现上述效果:

#include <iostream>
using namespace std;


constexpr int MACHINE = 80; 

template<int VERSION, typename Policy, typename PrePolicy>
struct ChainedPolicy
{
    using ActivePolicy = typename std::conditional<(VERSION>MACHINE), typename PrePolicy::ActivePolicy, Policy>::type;
};

template<int VERSION, typename Policy>
struct ChainedPolicy<VERSION, Policy, Policy>
{
        using ActivePolicy = Policy;
};

struct Policy50 : ChainedPolicy<50, Policy50, Policy50>
{
        static constexpr int M = 50; 
        static constexpr int N = 50; 
};
struct Policy70 : ChainedPolicy<70, Policy70, Policy50>
{
        static constexpr int M = 70; 
        static constexpr int N = 70; 
};
struct Policy80 : ChainedPolicy<80, Policy80, Policy70>
{
        static constexpr int M = 80; 
        static constexpr int N = 80; 
};
struct Policy85 : ChainedPolicy<85, Policy85, Policy80>
{
        static constexpr int M = 85; 
        static constexpr int N = 85; 
};
struct Policy90 : ChainedPolicy<90, Policy90, Policy85>
{
        static constexpr int M = 90; 
        static constexpr int N = 90; 
};
using Arch = Policy90;

int main()
{
        Arch::ActivePolicy a;
        std::cout<<a.M<<std::endl;
}

上面的设计可以达到目的,假如机器是80的arch,那么最终生效的就是Policy80, 好了目前为止又掌握了一个模板炫技的戏法。

奇异递归模板

上面是一个很好的例子,这个例子的本质就是奇异递归模板,下面好好研究一下这一个编程技术,原理是啥,使用场景是啥?
CRTP(Curiously Recurring Template Pattern)是一种使用C++模板元编程技术的设计模式,用于实现静态多态性。它是通过在派生类中继承基类,并将派生类自身作为基类的模板参数来实现的。具体而言,CRTP允许派生类在编译时通过继承和重载来覆盖基类的行为,而不需要运行时的虚函数调用。
常见的使用方式是:

template <typename D> class Base{/*do something*/};
class Derived : public Base<Derived> {/*do something*/};

这个看起来就是很奇怪,一个类型里面包含了一个继承于自己的类,这个话说起来就很费劲,所以一旦用这个编程技巧,可读性也是直线下降,常用在某些函数无法声明为虚函数的时候,下面是个小栗子:

template <typename D>
struct Base
{
	template<typename T>
	void Func(T& input) {
		D* ptr = static_cast<D*>(this);//注意这里用static_cast,其实也不安全,自己把握,我感觉个reinterpret_cast没啥区别
		ptr->Imp(input);
	}
};

struct Derive: public Base<Derive>
{
	template<typename T>
	void Imp(T& input){}
}

Derive d;
d.Func(in);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值