使用constexpr,可以在编译时或运行时根据参数计算函数.但通常,算法必须在编译时和运行时之间有所不同.例如.考虑constexpr版本的factorial.
constexpr int fact(int n) { return (n)?n*fact(n-1):1; }
如果n在运行时发生,那么函数效率低于一个forloop?是否有一些模板魔术来确定函数是在编译时还是在运行时执行并使用不同的算法?
更新:
factorial只是一个例子.如果没有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,也是运行时尽可能高效的.
解决方法
不,据我所知,您无法检测编译器在给定调用中如何使用该函数,或者指示编译器根据constness使用不同的实现.
但首先,constexpr函数仅限于单个return语句,这意味着编译器可以(通常)轻松应用尾递归优化,将递归调用转换为循环.因此,这个问题是关于如何进行过早优化,这不是一个好主意.低级优化是编译器的工作:让它.
其次,如果你真的想要编译器的工作,那么你可以命名函数,而不是试图将两个不同的函数实现无意义地塞进一个函数中.出于什么目的服务?只是默默无闻.
对于给出的特定示例,
constexpr int fact(int n) { return (n)?n*fact(n-1):1; }
编译器必须认识到它可以被重写为tail-recursive.我回忆起我之前关于它的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 ); }
免责声明:编译器脏手无法触及代码.