Mik*_*x7f 5 c++ templates c++11
我有一个模板函数(在我的例子中是一个 cuda 内核),其中有少量布尔模板参数可以在运行时选择。我很高兴在编译时实例化所有排列并动态调度,就像这样(对于布尔值 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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这写起来很烦人,如果我最终得到 b3 和 b4,情况会变得更糟。
有没有一种简单的方法可以在 C++11/14 中以更简洁的方式重写它而不引入大型外部库(如 boost)?就像是:
const auto dispatcher = construct_dispatcher<bool, 3>(myFunc);
Run Code Online (Sandbox Code Playgroud)
...
dispatcher(b0,b1,b2,otherArgs,args);
Run Code Online (Sandbox Code Playgroud)
没问题。
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{}... );
}
};
Run Code Online (Sandbox Code Playgroud)
kbool变量也是 如此,代表编译时常量布尔值。dispatch_bools是一个辅助结构,具有operator().
这operator()需要一组运行bool时,并从开始max-1产生最大的 if/else 分支,每个分支递归到调用dispatch_bools,并计算出另一个编译时 bool 。
这会生成 2^max 代码;正是您不想编写的代码。
延续一直向下传递到底部递归(其中max=0)。此时,所有编译时布尔值都已构建完毕——我们将continuation::operator()这些编译时布尔值作为函数参数传递。
希望continuation::operator()是一个可以接受编译时布尔值的模板函数。如果是,则有 2^max 个实例,每个实例都有 2^max 种可能的真/假组合。
要使用它来解决c++14中的问题,您只需执行以下操作:
std::array<bool, 3> bargs={{b0, b1, b2}};
dispatch_bools<3>{}(bargs, [&](auto...Bargs){
myFunc<decltype(Bargs)::value...,otherArgs>(args);
});
Run Code Online (Sandbox Code Playgroud)
这很容易,因为c++14有autolambda;它可以operator()在 lambda 上有一个模板。将这些编译时布尔参数转换回模板非类型参数很容易。
请注意,许多名义上的c++11编译器都支持自动 lambda,因为它非常简单。但是,如果缺少它,您仍然可以在c++11中使用辅助结构来解决此问题:
template<class OtherArgs>
struct callMyFunc {
Args args;
template<class...Bools>
void operator()(Bools...){
myFunc<Bools::value...,otherArgs>(args);
}
};
Run Code Online (Sandbox Code Playgroud)
现在使用的是:
std::array<bool, 3> bargs={{b0, b1, b2}};
dispatch_bools<3>{}(bargs, callMyFunc<otherArgs>{args});
Run Code Online (Sandbox Code Playgroud)
这基本上是手动编写c++14 lambda 的功能。
在c++14中,您可以替换void为auto并返回,而不仅仅是递归,它会很好地为您推导出返回类型。
如果您想要c++11中的该功能,您可以编写大量decltype代码,也可以使用以下宏:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
Run Code Online (Sandbox Code Playgroud)
并写出类似的正文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{}... )
)
Run Code Online (Sandbox Code Playgroud)
与专业化类似,并在c++11<0>中获得c++14样式的返回扣除。
RETURNS使得推断单行函数的返回类型变得微不足道。
| 归档时间: |
|
| 查看次数: |
616 次 |
| 最近记录: |