c++ - 有没有办法在编译时和运行时之间专门化一个函数?

标签 c++ c++11 constexpr

使用 constexpr,可以根据参数在编译时或运行时计算函数。但通常,编译时和运行时的算法必须不同。例如。考虑阶乘的 constexpr 版本。

constexpr int fact(int n)
{
return (n)?n*fact(n-1):1;
}

如果 n 发生在运行时,该函数是否比一个 forloop 效率低?是否有一些模板魔术来确定函数是在编译时还是运行时执行并使用不同的算法?

更新:
阶乘只是一个例子。所有 constexpr 函数是否都像在没有 constexpr 限制的情况下编码时一样高效? 例如:

constexpr int combinations(int n, int k)
{
//Assume all error conditions and edge conditions are taken care with ternary operator ?:
return fact(n)/(fact(k)*fact(n-k);
}

如果函数是在运行时编写的,它可以受益于Memoization .即使这是可能的,我想也很难表达函数,使其既 constexpr 又在运行时尽可能高效。

最佳答案

不,据我所知,您无法检测编译器如何在给定调用中使用函数,也无法指示编译器根据常量使用不同的实现。

但首先,constexpr 函数仅限于单个 return 语句,这意味着编译器可以(通常)轻松应用尾递归优化,转循环中的递归调用。因此,这个问题是关于如何进行过早优化的,这不是一个好主意。低级优化是编译器的工作:顺其自然。

其次,如果你真的真的想做编译器的工作,那么你可以命名函数,而不是试图毫无意义地将两个不同的函数实现塞进一个函数实现中。这样做的目的是什么?只有默默无闻。


对于给出的特定示例,

constexpr int fact(int n)
{
    return (n)?n*fact(n-1):1;
}

编译器必须认识到它可以被重写为尾递归。正如我从我之前对一个关于它的 SO 问题的测试中回想起的那样,即使是 Visual C++ 编译器也会这样做。虽然由于某些无法解释的原因(可能与原始 x86 处理器设计有关)它被浮点类型的使用难住了:相同的高级逻辑,不同的低级结果。

作为稍微不那么激烈的帮助编译器工作的努力,在测量并发现此函数是使您的应用程序慢得无法接受的函数之后,在检查机器代码并发现编译器无法识别函数的尾递归,你可以重写如下:

constexpr int fact( int multiplier, int n )
{
    return (n != 0? fact( multiplier*n, n-1 ) : multiplier);
}

constexpr int fact( int n )
{
    return fact( 1, n );
}

免责声明:代码未被编译器的脏手触及。

关于c++ - 有没有办法在编译时和运行时之间专门化一个函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14394605/

相关文章:

c++ - C Socket 和 Omnet++ 之间的方法名称冲突

C++:为什么这个 constexpr 模板函数会在 VS2017 中导致内部错误?(在 gcc 中是可以的)

c++ - 强制表达式为 constexpr

c++ - 在 C++11/14 中说 "foo not in {bar, baz}"的漂亮方式

c++ - 即使实例化不是 constexpr,声明为 constexpr 的模板函数是否始终内联?

c++ - OpenCV是否用零初始化权重矩阵,cv::ml::ANN_MLP

c++ - 在磁盘上实现的 FIFO 队列(或堆栈),而不是 ram(最好在 C++ 中)

c++ - 链接器错误已定义

c++11 - 配置错误 "A compiler with support for C++11 language features is required."

c++ - 在 C++ 中包含头文件时尖括号 < > 和双引号 ""之间的区别?