我想在编译时知道条件为false时能够避免调用函数。现在我使用这样的东西:
template<bool Enabled>
void fun(params)
{
//do nothing
}
template<>
void fun<true>(params)
{
//do something with params.
}
我不喜欢这种方法,即使函数体是空的,也会评估params
。
我想要一个解决方案,当函数没有被调用时,当条件为假时,不会评估params(这可能在第一种情况下使用空函数进行优化,但我不能假设这是每个编译器都为true。
这甚至可能吗?
答案 0 :(得分:13)
是的。
template<bool b, typename Func, typename FuncElse>
struct compile_time_if_functor {
void operator()( Func&& f, FuncElse&& ) const{
std::forward<Func>(f)();
}
};
template<typename Func, typename FuncElse>
struct compile_time_if_functor<false, Func, FuncElse> {
void operator()( Func&&, FuncElse&& else_f ) const{
std:forward<FuncElse>(else_f)();
}
};
template<bool b, typename Func, typename Else>
void compile_time_if( Func&& f, Else&& elsef ) {
compile_time_if_functor<b, Func, Else> functor;
functor(
std::forward<Func>(f),
std::forward<Else>(elsef)
);
}
template<bool b, typename Func>
void compile_time_if( Func&& f ) {
auto do_nothing = []{};
compile_time_if<b>( std::forward<Func>(f), std::move(do_nothing) );
}
使用:
int main() {
compile_time_if<expression>([&]{
// code that runs iff expression is true
});
compile_time_if<expression2>([&]{
// code that runs iff expression2 is true
},[&]{
// else clause, runs iff expression2 is false
});
}
请注意,{}
中的代码已编译,但如果它位于if
的错误分支中,则不会运行。因此,代码需要在类型级别上形成良好且合法,但在运行时执行并不一定合法。没有在那些lambdas中创建大小为0的数组!
一个更高级的方法可以让你无限地链接if-else块。如果我想这样做,我会使用命名操作员技巧。
首先,将compile_time_if
更改为返回std::integral_constant< bool, b >
。
然后,写下compile_time_else(Func&&)
和compile_time_elseif<bool>(Func&&)
,它们返回打包Func
并覆盖operator*( std::true_type, X )
和operator*( std::false_type, X )
以运行或不运行Func
的类型}并返回std::true_type
或std::false_type
。
最终目标是这种语法:
If<expression>([&]{
// block 1
})*Else([&]{
// block 2
});
If<expression>([&]{
// block 1
})*ElseIf<expression2>([&]{
// block 2
})*ElseIf<expression3>([&]{
// block 3
})*Else([&]{
// block 4
});
允许全开级联流量控制。你甚至可以这么做:
compile_time_switch<value>(
Case<c0, FallThrough>(),
Case<c1>([&]{
// block 1
}),
Case<c2, Continue>([&]{
// block 2
}),
Case<c3>([&]{
// block 3
}),
Case<c4>([&]->CanContinue{
// block 4
if (condition) {
return Continue;
} else {
return Break;
}
}),
Case<c4>([&]{
}),
Default([&]{
})
};
但这已经超越了我们自己。
有关如何以允许编译器在编译时操作流控制的方式来复制C ++语法的想法,请查看boost phoenix。我只是把它包含在这里是为了完整性:实际上写这种东西并不是那么实用,因为一些可怜的草皮将不得不维护它,并且你最初几次写这些东西你将会做一份糟糕的工作!