Frage

Wie Sie wahrscheinlich wissen, führt C ++ 11 die vor constexpr Stichwort.

C ++ 11 führte das Schlüsselwort contexpr ein, mit dem der Benutzer garantiert, dass eine Funktion oder ein Objektkonstruktor eine Kompilierungszeitkonstante ist. [...] Dies ermöglicht es dem Compiler, zu verstehen und zu überprüfen, ob [Funktionsname] eine Kompilierungszeitkonstante ist.

Meine Frage ist, warum es so strenge Einschränkungen der Form der Funktionen gibt, die deklariert werden können. Ich verstehe den Wunsch zu garantieren, dass die Funktion rein ist, aber denken Sie daran:

Die Verwendung von ConstExPR für eine Funktion führt einige Einschränkungen für die Funktionsweise dieser Funktion. Zunächst muss die Funktion einen Nicht-Void-Rückgabetyp haben. Zweitens kann der Funktionskörper keine Variablen deklarieren oder neue Typen definieren. Drittens kann die Leiche nur Deklarationen, Null -Anweisungen und eine einzelne Return -Anweisung enthalten. Es muss Argumentwerte vorliegen, so dass der Ausdruck in der Rückgabeerklärung nach der Argumentsubstitution einen konstanten Ausdruck erzeugt.

Das bedeutet, dass diese reine Funktion illegal ist:

constexpr int maybeInCppC1Y(int a, int b)
{
    if (a>0)
        return a+b;
    else
        return a-b;
  //can be written as   return  (a>0) ? (a+b):(a-b); but that isnt the point
}

Sie können auch nicht lokale Variablen definieren ... :( Ich frage mich, dass dies eine Designentscheidung ist, oder saugen Compiler, wenn es darum geht, die Funktion zu beweisen. A ist rein?

War es hilfreich?

Lösung

Der Grund, warum Sie Aussagen anstelle von Ausdrücken schreiben müssen, ist, dass Sie die zusätzlichen Funktionen von Aussagen, insbesondere die Fähigkeit zur Schleifen, nutzen möchten. Um nützlich zu sein, würde dies die Fähigkeit erfordern, Variablen zu deklarieren (auch verboten).

Wenn Sie eine Einrichtung zum Schleifen mit veränderlichen Variablen mit logischer Verzweigung kombinieren (wie in if Aussagen) Dann können Sie unendliche Schleifen erstellen. Es ist nicht möglich festzustellen, ob eine solche Schleife jemals endet (das Stoppproblem). Somit würden einige Quellen dazu führen, dass der Compiler hängt.

Durch die Verwendung rekursiver reine Funktionen ist es möglich, unendliche Rekursion zu verursachen, was sich als äquivalent leistungsfähig für die oben beschriebenen Schleifenfunktionen ausweist. C ++ hat jedoch bereits dieses Problem zur Kompilierungszeit - es tritt bei der Vorlagenerweiterung auf - und daher müssen Compiler bereits einen Schalter für die "Vorlagenstapel -Tiefe" haben, damit sie wissen, wann sie aufgeben müssen.

Die Einschränkungen scheinen also sicherzustellen, dass dieses Problem (zu bestimmen, ob eine C ++ - Zusammenstellung jemals fertig ist) keinen Dornierer als bereits ist.

Andere Tipps

Die Regeln für constexpr Funktionen sind so gestaltet, dass es ist unmöglich zu schreiben a constexpr Funktion mit Nebenwirkungen.

Durch erforderlich constexpr Um keine Nebenwirkungen zu haben, wird es für einen Benutzer unmöglich zu bestimmen, wo/wann er tatsächlich bewertet wurde. Das ist seitdem wichtig constexpr Funktionen dürfen nach Ermessen des Compilers sowohl zur Kompilierzeit als auch zur Laufzeit auftreten.

Wenn Nebenwirkungen erlaubt wären, müsste einige Regeln für die Reihenfolge bestehen, in der sie beobachtet werden würden. Das wäre unglaublich schwer zu definieren - noch schwieriger als die static Initialisierungsauftragsproblem.

Eine relativ einfache Regelung von Regeln für die Gewährleistung dieser Funktionen, um eine Nebenwirkung frei zu sein, besteht darin, dass sie nur ein einziger Ausdruck sind (mit ein paar zusätzlichen Einschränkungen darüber hinaus). Dies klingt zunächst einschränkend und schließt die IF -Aussage aus, wie Sie festgestellt haben. Während dieser bestimmte Fall keine Nebenwirkungen hätte, hätte er zusätzliche Komplexität in die Regeln eingeführt und angesichts der Tatsache, dass Sie die gleichen Dinge mit dem ternären Operator schreiben können oder rekursiv nicht wirklich eine große Sache ist.

N2235 ist das Papier, das die vorgeschlagen hat constexpr Zugabe in C ++. Es wird das Rationale für das Design erörtert - das relevante Zitat scheint dieses aus einer Diskussion über Zerstörer zu sein, aber im Allgemeinen relevant:

Der Grund dafür ist, dass eine konstante Expression vom Compiler zu Übersetzungszeiten genauso bewertet werden soll, genau wie jedes andere wörtliche eingebaute Typ; Insbesondere ist kein beobachtbarer Nebeneffekt zulässig.

Interessanterweise erwähnt das Papier auch, dass ein früherer Vorschlag vorgeschlagen hat, dass der Compiler automatisch herausgefunden hat, welche Funktionen waren constexpr Ohne das neue Keyword, aber dies wurde als unerbittlich komplex erwiesen, was meinen Vorschlag zu stützen scheint, dass die Regeln einfach so ausgelegt waren.

(Ich vermute, dass es in den im Papier genannten Referenzen andere Zitate geben wird, aber dies deckt den Schlüsselpunkt meines Arguments über die No-Nebenwirkungen ab)

Tatsächlich überlegt das C ++ - Standardisierungskomitee darüber, mehrere dieser Einschränkungen für C ++ 14 zu beseitigen. Siehe das folgende Arbeitsdokument http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3597.html

Die Einschränkungen könnten sicherlich ein wenig aufgehoben werden, ohne Code zu aktivieren, der während der Kompilierung nicht ausgeführt werden kann oder die nicht immer nachweislich nachweist. Ich denke jedoch, dass es nicht getan wurde, weil

  • Es würde den Compiler für einen minimalen Gewinn erschweren. C ++ - Compiler sind so komplex, wie es ist

  • genau anzugeben, wie viel zulässig ist, ohne die oben genannten Einschränkungen zu verletzen, wäre zeitaufwändig gewesen, und da die gewünschten Funktionen verschoben wurden, um den Standard aus der Tür herauszuholen der Standard) für wenig Gewinn

  • Einige der Einschränkungen wären entweder eher willkürlich oder eher kompliziert gewesen (insbesondere bei Schleifen, da C ++ nicht über das Konzept einer nativen Inkrementierung für die Schleife verfügt, aber sowohl die Endbedingung als auch der Inkrementcode müssen ausdrücklich in der angegeben werden Für die Erklärung können beliebige Ausdrücke für sie verwendet werden)

Natürlich konnte nur ein Mitglied des Standardausschusses eine maßgebliche Antwort geben, ob meine Annahmen korrekt sind.

Ich denke, Contexpr ist nur für Const -Objekte. Ich meine; Sie können jetzt statische Const -Objekte wie haben String::empty_string konstruiert statisch (ohne Hacking!). Dies kann die Zeit verkürzt, bevor 'Main' gerufen wurde. Und statische Const -Objekte können Funktionen wie haben .length(), operator==,... Deshalb wird also 'EXPR' benötigt. In 'C' können Sie statische konstante Strukturen erstellen, wie unten:

static const Foos foo = { .a = 1, .b = 2, };

Linux -Kernel hat Tonnen dieser Typklassen. In C ++ könnten Sie dies jetzt mit Colexpr tun.

HINWEIS: Ich weiß nicht, aber der Code unten sollte nicht akzeptiert werden, so wie bei der Version:

constexpr int maybeInCppC1Y(int a, int b) { return (a > 0) ? (a + b) : (a - b); }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top