在constexpr上对constexpr评估/重载进行分支

时间:2017-02-09 09:18:22

标签: c++ c++14 simd constexpr intrinsics

设置:

我有一个使用SIMD内在函数的函数,并希望在一些constexpr函数中使用它。

为此,我需要让它成为constexpr。但是,SIMD内在函数未标记为constexpr,并且编译器的常量赋值器无法处理它们。

我尝试用C ++ constexpr实现替换SIMD内在函数,它实现了同样的功能。该函数在运行时变慢了3.5倍,但我能够在编译时使用它(是吗?)。

问题

如何在常量表达式中使用 this function 而不会在运行时减慢我的程序?

一些想法:

  • 为所有编译器添加对常量评估所有SIMD内在函数到编译器常量表达式求值程序的支持:可能是正确的解决方案,但是一个不可能的巨大任务。

更实用的解决方案是:

  • 根据函数是否在常量表达式中执行(即提供constexpr和非constexpr版本)来重载函数。
  • 或者,以某种方式在constexpr和运行时实现之间的constexpr函数内分支(即,在分支中检测函数是否在常量表达式内执行)。

无论如何,我对任何可以解决我问题的建议持开放态度。

提示

  • @RMartinhoFernandes在休息室建议使用__builtin_constant_p来检测函数参数是否都是常量表达式,在这种情况下编译器至少会尝试在编译时评估函数。

尝试失败

  • @Jarod42提出了仅仅使用两个独立功能的直接建议。我想简单地指出为什么这不起作用,因为它不是微不足道的。该解决方案假设在呼叫站点处,是否将对constexpr进行评估。但这种情况并非如此。考虑一个调用我的constexpr函数,我应该选择哪个版本的函数?它必须选择constexpr才能编译,但是“外部”constexpr函数仍然可以在运行时进行评估。在这种情况下,它将使用“慢”编译时实现,因此,这种方法无法解决问题。

1 个答案:

答案 0 :(得分:4)

我会这样做

constexpr int doit(int input, bool inconst = false) {
   return inconst ? doitconsty(input) : doitfast(input);
}

如果对doit的调用是在constexpr函数内部,可以调用它来在运行时或编译时执行某些操作,只需转发标志

constexpr int f(int n, bool inconst = false) {
   /* ... */
   int importantInt = doit(n / 42, inconst);
   /* ... */
   return magicResult;
}

如果我没有弄错的话,任何constexpr评估都会有所启动。通过inconst那里

enum foo { bar = f(256, true) }

如果您在运行时世界,只需像其他任何事情一样致电f

int main() { std::cout << "test-case: " << f(256); }

应该注意,这对运算符不起作用,因为你不能在那里添加布尔参数。相反,你可以用不同的方式传递值,如果这对你来说很好(对于像intbool这样的原始值,我们也不能重载运算符)。

template<typename T>
struct maybe_const_value {
   T t;
   bool isconst;
};

enum foo { bar = maybe_const_value{256, true} % magicTransform }; 

int main() { return maybe_const_value{265} % magicTransform; }

然后,操作员功能可以检查input.isconst并使用input.t作为实际值。