poprawność std :: function const

11

Załóżmy, że mam typ na żądanie:

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

Zauważ, że mutable_callablema non-const, operator()która modyfikuje zmienną składową .....

Załóżmy teraz, że utworzyłem std::functionz mojego typu:

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

Teraz mogę to zrobić:

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

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

Teraz, o ile mogę powiedzieć, std::functions operator()jest constwedług: https://en.cppreference.com/w/cpp/utility/functional/function/operator ()

Więc mam przeczucie, że nie powinieneś być w stanie tego zrobić .....

Ale potem patrząc na: https://en.cppreference.com/w/cpp/utility/functional/function/function

To nie wydaje się ograniczać, czy typ wywoływalny ma stałą operator()......

Moje pytanie brzmi więc: mam rację, zakładając, że std::function<int()> const&jest to w zasadzie to samo, std::function<int()>&że nie ma żadnej różnicy między zachowaniem tych dwóch ...... a jeśli tak, to dlaczego nie jest constpoprawne?

DarthRubik
źródło
@ MaxLanghof No ..... std::functionma odpowiednik struct a{ std::any x; };w nim .....
DarthRubik
Oto mały fragment wewnętrznych elementów std::functionimplementacji MSVC : i.stack.imgur.com/eNenN.png gdzie using _Ptrt = _Func_base<_Ret, _Types...>. Opieram swoją sprawę.
Max Langhof,

Odpowiedzi:

3

To sprowadza się do tego samego, jak struct A { int* x; };, gdzie w sposób const A a;można zmodyfikować wartość z *(a.x)(ale nie tam, gdzie to wskazuje). Istnieje poziom pośrednictwa w std::function(od typu wymazywania), przez który constnie jest propagowany.

I nie, std::function<int()> const& fnie jest bez sensu. W przypadku std::function<int()>& fmożesz przypisać inny funktor f, czego nie można zrobić w tym constprzypadku.

Max Langhof
źródło
Tak ... to naprawdę ma sens ... na pierwszy rzut oka jednak
mylące
Uważam, że to wada projektowa. Ta pośrednia powinna być szczegółem implementacji przejrzystym dla użytkownika, a ciągłość może być propagowana przy użyciu niektórych metaprogramowania.
Igor R.
@IgorR. Tak, stałość może być propagowana. std::vectorrobi to, std::unique_ptrnie robi. Wydaje mi się, że std::functiontak naprawdę nie chodzi o wyrażanie niezmienników stanu funktora. Może moglibyśmy zmienić przeznaczenie obrzydliwych typów funkcji (tj. std::function<int() const>) W celu rozróżnienia?
Max Langhof,
unique_ptrnie powinien propagować stałości, tak jak zwykły wskaźnik. I std::function<int() const>nie chciałbym się skompilować.
Igor R.
@IgorR. Wiem. Chodzi mi o to, że niektóre części standardowej biblioteki to robią, a inne nie. Która kategoria std::functionpowinna należeć do mnie nie jest jasne. I std::function<int() const>był hipotetyczny - oczywiście, że teraz się nie kompiluje, ale czy spełniłby on np. OP tutaj, gdyby można go było uznać za ważny, wyrażając „można przypisać funktory tylko z operator() const(lub bezpaństwowcami)”? (nawet jeśli za kulisami byłoby to dość okropne, ze względu na stosowanie ohydnych typów funkcji)?
Max Langhof,