我有一堆如下代码:
int sign(MyEnum e)
{
switch(e)
{
case A:
case B:
return 1;
case C:
case D:
return -1;
default:
throw new std::runtime_error("Invalid enum value");
}
}
int f(int a, int b, int c, MyEnum e)
{
const int sign = sign(e);
const int x = a * b - sign * c;
const int y = a + sign * c;
return x / y;
}
这里的算法只是一个例子。实际的代码更加复杂,但是要点是,sign
取决于枚举值是-1还是1,并且我们进行了大量的计算,其中各种事情都乘以sign
。 (编辑:枚举值在编译时未知。)
我希望对这段代码进行优化,就像我写了以下代码一样:
int f(int a, int b, int c, MyEnum e)
{
switch(e)
{
case A:
case B:
{
const int x = a * b - c;
const int y = a + c;
return x / y;
}
case C:
case D:
{
const int x = a * b + c;
const int y = a - c;
return x / y;
}
default:
throw new std::runtime_error("Invalid enum value");
}
}
当然,我实际上并不想编写所有这样的代码,因为这是测试和维护的噩梦。
使用Compiler Explorer,似乎sign
中的异常可能是这里的问题;如果我有“默认”情况下的返回值,例如-1,那么我得到了我想要的。但是我想在这里一些安全。
问题:
-O3
上进行了编译,对方法进行了两个克隆,其中一个克隆完成了我想要的操作,尽管我不知道哪个实际上可以运行。我可以为此提供提示吗?-O3
编译一切。我可以仅针对特定的代码块启用优化,还是鼓励编译器进行优化?编辑:由于我(显然)不了解当前遇到的所有问题,因此我可能没有给这个标题冠冕堂皇。如果您知道自己在做什么,请随时进行编辑。
答案 0 :(得分:6)
这是另一种选择:
template <int sign>
int f(int a, int b, int c)
{
const int x = a * b - sign * c;
const int y = a + sign * c;
return x / y;
}
int f(int a, int b, int c, MyEnum e)
{
const int sign = sign(e);
if (sign == 1) return f<1>(a, b, c);
else return f<-1>(a, b, c);
}
通过这种方式,您可以保留想要的安全性(以异常的形式),但是随后将所得信息转换为编译时值,编译器可以使用该值进行优化。
正如Chris在评论中指出的那样,如果sign
仅用于切换c
的符号,则可以完全摆脱模板,而只需翻转{{1} }在致电时的符号:
c
答案 1 :(得分:3)
由于在这种情况下,int sign(MyEnum)
的功能未被其他翻译单元使用,因此可以将其标记为static
。
在这种情况下,static
表示该功能在翻译单元本地,并且不链接到该翻译单元之外。 (根据使用的上下文,关键字static
在C ++中具有不同的含义。)
这使优化器可以执行更多优化,并可能会完全消除该功能(假设启用了优化)。