C++: Funktion als "pure" markieren



  • Ich zitiere mal aus der gcc-Hilfe: "returns a value depending only on its arguments (pure)"

    Kann man das auch mit Standard-C++ machen?



  • Ich hab eigentlich keine Ahnung, aber wenn ich das lese

    pure
    Many functions have no effects except the return value and their return value depends only on the parameters and/or global variables. Such a function can be subject to common subexpression elimination and loop optimization just as an arithmetic operator would be. These functions should be declared with the attribute pure. For example,

    int square (int) __attribute__ ((pure));

    says that the hypothetical function square is safe to call fewer times than the program says.

    Some of common examples of pure functions are strlen or memcmp. Interesting non-pure functions are functions with infinite loops or those depending on volatile memory or other system resource, that may change between two consecutive calls (such as feof in a multithreading environment).

    Dann zündet bei mir sowas:

    #include <iostream>
    
    template<typename T>
    constexpr auto sqr(T num) { return num * num; }
    
    int main()
    {
        std::cout << sqr(5) << '\n';
    }
    

    und sonst kenn ich noch inline , aber ich glaube das ist etwas anderes, da wird halt irgendwie der Funktionsaufruf eliminiert, oder so.



  • Ich glaube, constexpr ist etwas anderes. Das besagt, dass man den Funktionswert zur Compile-Zeit auswerten kann.



  • Soetwas wie gcc hat gibt es nicht im standard. Weiß auch nicht, wozu man das gebrauchen kann.



  • sdffds schrieb:

    Ich glaube, constexpr ist etwas anderes. Das besagt, dass man den Funktionswert zur Compile-Zeit auswerten kann.

    Ja, aber da eine constexpr Funktion, die aucht tatsächlich zur Compile-Zeit ausgewertet wird, weder globale Variablen verändern noch nicht-konstante globale Variablen lesen kann, ist sie pure.

    Die sqr() Funktion ist pure instantiert für Typen wie int, wo der operator*() auch constexpr ist. Für einen Typen, der beim multiplizieren Debug-Ausgaben macht, ist sie nicht pure, kann dann aber auch nicht zur Compilezeit ausgewertet werden.



  • Nathan schrieb:

    sdffds schrieb:

    Ich glaube, constexpr ist etwas anderes. Das besagt, dass man den Funktionswert zur Compile-Zeit auswerten kann.

    Ja, aber da eine constexpr Funktion, die aucht tatsächlich zur Compile-Zeit ausgewertet wird, weder globale Variablen verändern noch nicht-konstante globale Variablen lesen kann, ist sie pure.

    Aber umgekehrt -- und darauf kommt es mir an -- ist nicht jede pure-Funktion constexpr.


  • Mod

    dfsfdf schrieb:

    Ich zitiere mal aus der gcc-Hilfe: "returns a value depending only on its arguments (pure)"

    Kann man das auch mit Standard-C++ machen?

    Was, dem Compiler einen Tipp geben? Attribute sind natürlich portabel (insofern als dass keine praktische Implementierung das Attribut missverstehen wird). Oder möchtest du eine Funktion zu diesem Verhalten zwingen? Letzteres scheint nicht sinnvoll zu sein, und wäre auch nicht trivial zu implementieren. Vor allem würde ein derartiger Check false positives liefern, da der Rückgabewert durchaus nur von Argumenten abhängen kann, während im Funktionsrumpf ggf. globale Variablen odr-used werden.



  • Wenn ich so etwas hier lese:

    HarteWare schrieb:

    ... Such a function can be subject to common subexpression elimination... says that the hypothetical function square is safe to call fewer times than the program says...

    ... dann interpretiere ich das so, dass der Compiler z.B. so etwas hier machen darf:

    5 * sqr(x) - sqr(x) => 4 * sqr(x)

    Das kann durchaus nützlich sein, wenn man irgendwelche arithmetischen Klassen ( std::complex , Matrix/Vektorklassen) bzw. zugehörige Funktionen
    implementiert und möglichst optimalen Code herausholen will. Auch wenn es wohl am ehesten was für diejenigen ist, welche die Standardbibliothek für den Compiler implemenhtieren.

    Finnegan



  • So verstehe ich pure auch. Allerdings hoffe ich mal, dass der Compiler das in den meisten Fällen automatisch rauskriegt, ohne das man ein Attribut dran packt.


  • Mod

    sebi707 schrieb:

    So verstehe ich pure auch. Allerdings hoffe ich mal, dass der Compiler das in den meisten Fällen automatisch rauskriegt, ohne das man ein Attribut dran packt.

    Aber nur, wenn ihm der Code konkret vorliegt. Das Attribut wird wohl dafür gedacht sein, wenn man mehrere Übersetzungseinheiten hat.



  • sebi707 schrieb:

    So verstehe ich pure auch. Allerdings hoffe ich mal, dass der Compiler das in den meisten Fällen automatisch rauskriegt, ohne das man ein Attribut dran packt.

    Bei so etwas wie sqr für skalare Typen würde ich auch davon ausgehen.
    Wenn T z.B. eine Matrix ist, könnte sich der Compiler schon etwas schwerer tun, zweifelsfrei nachzuweisen, dass man das machen kann.
    Ich überlasse solche Sachen auch gerne dem Compiler - wenn eine Implementierung alleridings davon lebt, das der Compiler etwas bestimmtes macht,
    dann lasse ich lieber nichts anbrennen, und verwende auch compilerspezifische Attribute. So z.B. schonmal ausgiebige __forceinline bzw.
    __attribute__((always_inline)) an den passenden Stellen in Code, der mithilfe von Expression Templates SIMD-Instruktionen erzeugt hat
    (wäre witzlos wenn sich die Heuristik da gegen Inlining entscheiden würde).

    Finnegan


Log in to reply