动态分派到模板函数C ++ [英] Dynamic Dispatch to Template Function C++

查看:51
本文介绍了动态分派到模板函数C ++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个模板函数(在我的情况下是cuda内核),在运行时可以在其中选择少量布尔模板参数.我很高兴在编译时实例化所有排列并动态调度,就像这样(对于布尔b0,b1,b2):

I have a template function (in my case a cuda kernel), where there are a small number of boolean template parameters that can chosen between at runtime. I am happy to instantiate all permutations at compile time and dispatch dynamically, like so (for boolean b0,b1,b2):

if (b0) {
    if (b1) {
        if (b2) {
            myFunc<true,true,true,otherArgs>(args);
        } else {
            myFunc<true,true,false,otherArgs>(args);
        }
    } else {
        if(b2) {
            myFunc<true,false,true,otherArgs>(args);
        } else {
            myFunc<true,false,false,otherArgs>(args);
        }
    }
} else {
    if(b1) {
        if(b2) {
            myFunc<false,true,true,otherArgs>(args);
        } else {
            myFunc<false,true,false,otherArgs>(args);
        }
    } else {
        if(b2) {
            myFunc<false,false,true,otherArgs>(args);
        } else {
            myFunc<false,false,false,otherArgs>(args);
        }
    }
}

这很烦人,如果我最终得到b3和b4,则会成倍恶化.

This is annoying to write, and gets exponentially worse if I end up with a b3 and b4.

是否有一种简单的方法可以在C ++ 11/14中以更简洁的方式重写此代码,而无需引入大型外部库(例如boost)?像这样:

Is there a simple way to rewrite this in a more concise way in C++11/14 without bringing in large external libraries (like boost)? Something like:

const auto dispatcher = construct_dispatcher<bool, 3>(myFunc);

...

dispatcher(b0,b1,b2,otherArgs,args);

推荐答案

没问题.

template<bool b>
using kbool = std::integral_constant<bool, b>;

template<std::size_t max>
struct dispatch_bools {
  template<std::size_t N, class F, class...Bools>
  void operator()( std::array<bool, N> const& input, F&& continuation, Bools... )
  {
    if (input[max-1])
      dispatch_bools<max-1>{}( input, continuation, kbool<true>{}, Bools{}... );
    else
      dispatch_bools<max-1>{}( input, continuation, kbool<false>{}, Bools{}... );
  }
};
template<>
struct dispatch_bools<0> {
  template<std::size_t N, class F, class...Bools>
  void operator()( std::array<bool, N> const& input, F&& continuation, Bools... )
  {
     continuation( Bools{}... );
  }
};

在线示例.

所以 kbool 是一个变量,它表示一个编译时间常数布尔值. dispatch_bools 是一个具有 operator()的帮助程序结构.

So kbool is a variable with represents a compile time constant boolean. dispatch_bools is a helper struct that has an operator().

operator()接受运行时 bool s的数组,并从 max-1 开始继续生成最大if/else分支,每次递归调用 dispatch_bools 时,都会计算出一个编译时布尔值.

This operator() takes an array of runtime bools, and starting at max-1 proceeds to spawn max if/else branches, each recursing into call to dispatch_bools with one more compile-time bool calculated.

这将生成2 ^ max代码;正是您不想编写的代码.

This generates 2^max code; exactly the code you don't want to write.

连续性一直向下传递到底部递归(其中 max = 0 ).到那时,所有的编译时布尔都已经建立起来了,我们称之为 continuation :: operator(),将这些编译时布尔作为函数参数传入.

The continuation is passed all the way down to the bottom recursion (where max=0). At that point, all of the compile-time bools have been built up -- we call continuation::operator() passing in those compile-time bools as function parameters.

希望 continuation :: operator()是一个模板函数,可以接受编译时布尔.如果是,则有2 ^ max个实例化,每个实例都有2 ^ max个可能的真/假组合中的每一个.

Hopefully continuation::operator() is a template function that can accept compile-time bools. If it is, there are 2^max instantiations of it, each with each of the 2^max possible true/false combinations.

要使用它来解决您在

具有 auto lambdas;它可以在lambda上具有模板 operator().将这些编译时布尔参数转换回模板非类型参数很容易.

This is easy because c++14 has auto lambdas; it can have a template operator() on a lambda. Turning those compile-time bool arguments back into template non-type arguments is easy.

请注意,许多名义上编译器支持自动lambda,因为它很容易.但是,如果缺少它,您仍然可以在以及一个辅助结构:

Note that many nominally c++11 compilers support auto-lambdas, because of how easy it was. However, if you lack it, you can still solve this in c++11 with a helper struct:

template<class OtherArgs>
struct callMyFunc {
  Args args;
  template<class...Bools>
  void operator()(Bools...){
    myFunc<Bools::value...,otherArgs>(args);
  }
};

现在使用的是:

std::array<bool, 3> bargs={{b0, b1, b2}};
dispatch_bools<3>{}(bargs, callMyFunc<otherArgs>{args});

这基本上是手动编写

c ++ 14您可以将 void 替换为 auto 并返回而不仅仅是递归,这将为您合理地推断出返回类型.

In c++14 you can replace void with auto and return instead of just recursing and it will deduce a return type for you reasonably well.

如果您要在,您可以编写很多 decltype 代码,也可以使用以下宏:

If you want that feature in c++11 you can either write a lot of decltype code, or you can use this macro:

#define RETURNS(...) \
  noexcept(noexcept(__VA_ARGS__)) \
  -> decltype(__VA_ARGS__) \
  { return __VA_ARGS__; }

并编写 dispatch_bools 的正文,例如:

template<class T, std::size_t N, class F, class...Bools>
auto operator()( std::array<T, N> const& input, F&& continuation, Bools... )
RETURNS(
 (input[max-1])?
    dispatch_bools<max-1>{}( input, continutation, kbool<true>{}, Bools{}... )
 :
    dispatch_bools<max-1>{}( input, continutation, kbool<false>{}, Bools{}... )
)

以及类似的< 0> 专长,并获得样式的返回值扣除=显示标记为'c ++ 11'的问题""rel =" tag> c ++ 11 .

and similar for the <0> specialization, and get c++14 style return deduction in c++11.

RETURNS 使得推论单线函数的返回类型变得很简单.

RETURNS makes deducing return types of one-liner functions trivial.

这篇关于动态分派到模板函数C ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆