namespace - modern c++ best practice




C++-Erzwingen der Reihenfolge der Bewertung von Funktionsparametern (2)

Das Semikolon, das Anweisungen voneinander trennt, setzt eine "happen before" -Relation voraus. auto && a = increment() muss zuerst ausgewertet werden. Es ist garantiert. Das zurückgegebene temporäre Element wird vor dem zweiten Aufruf zum increment an die Referenz a gebunden (und ihre Lebensdauer verlängert).

Es gibt keine UB. Auf diese Weise können Sie eine Evaluierungsreihenfolge erzwingen.

Das einzige, was Sie hier sehen können, ist, dass Sie sich Sorgen machen müssen, wenn increment eine Referenz selbst zurückgibt. Aber wenn es keine lebenslangen Probleme gäbe, sagen wir, wenn es einen Verweis auf count gäbe, gäbe es immer noch kein UB aus der auferlegten Bewertung von a und dann b .

Ich verstehe das, wenn ich eine Funktion wie

a(b(),c());

dann kann das Verhalten in <= C ++ 14 undefiniert und in> = C ++ 17 nicht spezifiziert sein, in dem Sinne, dass es dem Compiler überlassen ist, zu bestimmen, ob b oder c zuerst ausgewertet werden sollen.

Ich würde gerne wissen, wie man eine Auswertungsanordnung am besten erzwingt. Ich werde als C ++ 14 kompilieren.

Das, was mir sofort einfällt, ist ungefähr so:

#include <iostream>

int count = 5;
auto increment(){
    return count++;
}

template <typename A, typename B>
auto diff(A && a, B && b){
   return a - b;
}

int main() {
    auto && a = increment();
    auto && b = increment();
    auto c = diff(a,b);
}

Bin ich in undefiniertem Verhaltensland? Oder soll man so die Auswertungsreihenfolge "erzwingen"?


Hier ist eine andere Möglichkeit, die Auswertungsreihenfolge mithilfe einer std::initializer_list zu erzwingen, die eine garantierte Auswertungsreihenfolge von links nach rechts aufweist:

#include <numeric> // for accumulate
#include <initializer_list>

template <class T>
auto diff(std::initializer_list<T> args)
{
   return std::accumulate(args.begin(), args.end(), T(0), std::minus<>{});
}

const auto result = diff({increment(), increment()});

Dies beschränkt Sie auf Objekte desselben Typs und Sie müssen zusätzliche geschweifte Klammern eingeben.





c++14