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

Mir*_*pas 3 c++ template-function c++11 static-if

我希望能够避免在条件为false时调用函数,这在编译时已知.现在我使用这样的东西:

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

template<>
void fun<true>(params)
{
    //do something with params.
}
Run Code Online (Sandbox Code Playgroud)

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

我想要一个解决方案,当根本没有调用该函数时,当条件为假时,不会对params进行求值(这可能在第一种情况下使用空函数进行优化,但我不能认为这是真的.编译器).

这甚至可能吗?

Yak*_*ont 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) );
}
Run Code Online (Sandbox Code Playgroud)

使用:

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
  });
}
Run Code Online (Sandbox Code Playgroud)

请注意,里面的代码{}是编译的,但是如果它在错误的分支中则不会运行if.因此,代码需要在类型级别上形成良好且合法,但在运行时执行并不一定合法.在这些lambda中没有创建大小为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
});
Run Code Online (Sandbox Code Playgroud)

允许全程级联流量控制.你甚至可以做到:

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([&]{
  })
};
Run Code Online (Sandbox Code Playgroud)

但那是领先于我们自己.

有关如何以允许编译器在编译时操作流控制的方式来复制C++语法的想法,请查看boost phoenix.我只是把它包含在这里是为了完整性:实际上写这种东西并不是那么实用,因为一些可怜的草皮将不得不维护它,并且你最初几次写这些东西你将会做一份糟糕的工作!