在编译时评估表达式

Rei*_*ski 6 c# compiler-construction visual-studio

我知道这已被问过很多,但仅限于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  
Run Code Online (Sandbox Code Playgroud)

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

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

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

Pet*_*der 5

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

选项一:使用静态只读(启动时计算一次):

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

    public void Execute()
    {
        // .. whatever
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

    public void Execute()
    {
        // .. whatever
    }
}
Run Code Online (Sandbox Code Playgroud)

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

如果您希望在编译时执行尽可能多的操作,事情就会变得更加困难。在 C++ 下你有模板。我发现它们写起来很麻烦,但人们用它完成了令人惊奇的事情编译时函数似乎变得更容易,但我还没有尝试过。D有CTFE,确实很强大。但 D 是一个利基市场,我会避免在其中编写任何严肃的代码。我不知道其他语言具有相当多的显式预编译评估,但我确信有一些。

如今编译器非常聪明。编译器很可能会发现有机会在没有提示的情况下内联优化函数调用。在 DotNet 4.5 中,我们获得了AggressiveInlined属性,因此我们可能能够强制编译器进入正确的方向。C/C++ 有类似的东西并且存在问题。我这边的一般建议是避免这样做,inline直到您确切知道自己在做什么。

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

  1. 还没有(仅限专家)