在编译时评估表达式

evaluate expression at compile time

我知道这个问题被问了很多,但仅限于 C/C++ 和 Java。 问题与使用常量表达式的性能优势有关:

当我调用仅使用常量作为参数的静态函数时,有没有办法告诉编译器它应该在编译时评估调用并用结果替换调用?

示例:

const double pi = Math.PI; //works as Math.PI is a constant  
const double spi = Math.Sin(Math.PI); //compiler error, because expression must be constant  

是否没有指令(更好:属性)明确地告诉编译器像 Math.Sin() 这样的静态方法不会在内部修改或读取任何数据,因此在技术上可以评估调用在编译时?

哦,请不要像 "just do const double spi = 0" :) 那样回答,因为我的示例只是我遇到的问题的简化版本:在保持最佳性能的同时提高代码可维护性。

感谢您的帮助 - 非常感谢!

没有副作用的方法有 [Pure] 属性。但是,这仅用于代码分析,而不是由编译器(目前)使用。但是,这可能会在未来发生变化。

JetBrains ReSharper 提供了类似的 [Pure] 属性用于相同的目的(代码分析)。

因此,目前,您需要一个解决方法,例如您预先计算的值,最好附上评论,让其他人知道该值的来源:

const double spi = 0.0; // Math.Sin(Math.PI)

static readonly double spi = Math.Sin(Math.PI);

这当然会计算运行时的值,这是您不想要的。

对于数字常量,我看到两个选项:

方案一:使用static readonly(启动时计算一次):

class MyCalc
{
    private static readonly double spi = Math.Sin(Math.PI);
    private static readonly double pi = Math.PI;

    public void Execute()
    {
        // .. whatever
    }
}

选项二:使用袖珍计算器进行计算并对这些常量进行硬编码:

class MyCalc
{
    // Math.Sin(Math.Pi)
    private const double spi = 0;
    // Math.Pi
    private const double pi = 3.141592653589793;

    public void Execute()
    {
        // .. whatever
    }
}

我不确定,如果编译器可以在计算中完全优化选项一,但它应该是最可读和可维护的方式。

如果您希望在编译时做尽可能多的事情,事情就会变得更难。在 C++ 下你有模板。我发现它们写起来很麻烦,但人们得到 amazing things done with it. It seems it got easier with compile time functions but I haven't tried them yet. D have CTFE 这真的很强大。但 D 是一个小众市场,我会避免在其中编写任何严肃的代码。我不知道其他语言有相当多的显式预编译评估,但我确信有一些。

如今的编译器非常聪明。编译器很有可能会看到机会在没有提示的情况下内联优化函数调用。在 DotNet 4.5 中,我们得到了 AggressiveInlining-attribute so we might to be able to force the compiler into the right direction. C/C++ have something similar and there had been problems。我这边的一般建议是避免inline,直到你完全知道自己在做什么。

如果你真的不想从 C# 走这条路,在我看来最好的选择是使用提到的功能在 C++ 中编写你的功能,编写一个易于使用的 C 接口并通过 PInvoke。但是,如果真的值得,请先帮自己一个忙并衡量一下。永远不要忘记两个优化规则:

  1. 不要
  2. 还不知道(仅限专家)