避免在编译时错误条件下调用函数

时间:2013-04-27 20:48:29

标签: c++ c++11 template-function static-if

我想在编译时知道条件为false时能够避免调用函数。现在我使用这样的东西:

template<bool Enabled>
void fun(params)
{
    //do nothing
}

template<>
void fun<true>(params)
{
    //do something with params.
}

我不喜欢这种方法,即使函数体是空的,也会评估params

我想要一个解决方案,当函数没有被调用时,当条件为假时,不会评估params(这可能在第一种情况下使用空函数进行优化,但我不能假设这是每个编译器都为true。

这甚至可能吗?

1 个答案:

答案 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_typestd::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。我只是把它包含在这里是为了完整性:实际上写这种东西并不是那么实用,因为一些可怜的草皮将不得不维护它,并且你最初几次写这些东西你将会做一份糟糕的工作!