std :: function const Korrektheit

11

Angenommen, ich habe einen aufrufbaren Typ wie folgt:

struct mutable_callable
{
    int my_mutable = 0;
    int operator()() { // Not const
        return my_mutable++;
    }
};

Beachten Sie, dass mutable_callablees eine Nicht-Konstante gibt operator(), die eine Mitgliedsvariable ändert .....

Angenommen, ich erstelle ein std::functionOut aus meinem Typ:

std::function<int()> foo = mutable_callable{};

Jetzt kann ich das machen:

void invoke(std::function<int()> const& z)
{
    z();
}

int main()
{
    invoke(foo); // foo changed.....oops
}

Soweit ich das beurteilen kann, lautet std::functions wie operator()folgt const: https://en.cppreference.com/w/cpp/utility/functional/function/operator ()

Mein Bauchgefühl ist also, dass Sie dies nicht können sollten .....

Aber dann schauen Sie sich Folgendes an: https://en.cppreference.com/w/cpp/utility/functional/function/function

Dies scheint keine Einschränkungen dafür zu setzen, ob der aufrufbare Typ eine Konstante hat oder nicht operator()......

Meine Frage lautet also: Ich gehe zu Recht davon aus, dass dies std::function<int()> const&im Wesentlichen dasselbe ist, nämlich std::function<int()>&dass es keinen tatsächlichen Unterschied zwischen dem Verhalten der beiden gibt. Wenn dies der Fall ist, warum ist es dann nicht constrichtig?

DarthRubik
quelle
@ MaxLanghof Nein .....std::function hat das Äquivalent zu einem struct a{ std::any x; };darin .....
DarthRubik
Hier ist ein kleiner Ausschnitt der Interna des MSVC std::function Implementierung: i.stack.imgur.com/eNenN.png where using _Ptrt = _Func_base<_Ret, _Types...>. Ich ruhe meinen Fall aus.
Max Langhof

Antworten:

3

Dies läuft darauf hinaus struct A { int* x; };, wo Sie in a den Wert von const A a;ändern können (aber nicht, wohin er zeigt). Es gibt eine Indirektionsebene in (vom Typ Löschen), durch die nicht weitergegeben wird.*(a.x)std::functionconst

Und nein, std::function<int()> const& fist nicht sinnlos. In einem std::function<int()>& fkönnten Sie einen anderen Funktor zuweisen f, was Sie in diesem constFall nicht tun können.

Max Langhof
quelle
Yup ..... das macht eigentlich sehr viel Sinn ..... aber auf den ersten Blick immer noch verwirrend
DarthRubik
Ich glaube, es ist ein Designfehler. Diese Indirektion sollte ein Implementierungsdetail sein, das für den Benutzer transparent ist, und die Konstanz könnte unter Verwendung einer Metaprogrammierung weitergegeben werden.
Igor R.
@IgorR. Ja, die Konstanz könnte weitergegeben werden. std::vectortut das, std::unique_ptrnicht. Ich denke, es std::functiongeht nicht wirklich darum, Invarianten des Funktorzustands auszudrücken. Vielleicht könnten wir abscheuliche Funktionstypen (dh std::function<int() const>) zur Unterscheidung wiederverwenden ?
Max Langhof
unique_ptrsollte keine Konstanz verbreiten, wie dies der reguläre Zeiger nicht tut. Und std::function<int() const>würde nicht kompilieren.
Igor R.
@IgorR. Ich kenne. Mein Punkt war, dass einige Teile der Standardbibliothek dies tun und andere nicht. In welche Kategorie std::functionfallen soll, ist mir nicht klar. Und das std::function<int() const>war eine Hypothese - natürlich wird es jetzt nicht kompiliert, aber würde es zB das OP hier befriedigen, wenn dies gültig gemacht werden könnte und ausdrückt "kann nur Funktoren mit einem operator() const(oder staatenlosen) zugewiesen werden"? (Selbst wenn dies hinter den Kulissen aufgrund der Verwendung abscheulicher Funktionstypen ziemlich grausam wäre)?
Max Langhof