您可以使用通用lambda(C++14)来实现这样的功能。请注意,这需要您更改
Kernel::kernel
并且稍微改变内核的创建以允许自动类型推导:
内核
template<int SimdWidth, typename F, typename... Args>
class Kernel
{
public:
Kernel(F&& kernelPrm)
: kernel(std::move(kernelPrm))
{
}
void run(int n, Args... args)
{
const int nLoop = (n / SimdWidth);
for (int i = 0; i < nLoop; i++)
{
CallKernel(i * SimdWidth, SimdWidth, args...);
}
if ((n / SimdWidth) * SimdWidth != n)
{
const int m = n % SimdWidth;
for (int i = 0; i < m; i++)
{
CallKernel(nLoop * SimdWidth + i, 1, args...);
}
}
}
private:
// helper function creating the factory and passing it to kernel
void CallKernel(int simdGroupId, int simdWidth, Args... args)
{
const int id = simdGroupId;
if (simdWidth == SimdWidth)
{
const KernelDataFactory<SimdWidth> factory;
kernel(factory, id, args...);
}
else
{
const KernelDataFactory<1> factory;
kernel(factory, id, args...);
}
}
F kernel;
};
帮助者
这些助手是推导Kernel的第二个模板参数所必需的。
// helper for specifying the parameter pack
template<class...Args>
struct KernelArgs
{};
template<int SimdWidth, typename F, class...Args>
auto CreateKernel(F&& kernelPrm, KernelArgs<Args...> const&)
{
return Kernel<SimdWidth, F, Args...>(std::forward<F>(kernelPrm));
}
主要的
...
auto kernel = CreateKernel<simd>([](auto& factory, int const id, float* input, float* output)
{
auto a = factory.template generate<float>();
a.readFrom(input + id);
const auto b = a.sqrt().sqrt().sqrt().sqrt().sqrt().
sqrt().sqrt().sqrt().sqrt().sqrt().
sqrt().sqrt().sqrt().sqrt().sqrt();
b.writeTo(output + id);
}, KernelArgs<float*, float*>{});
...