std :: function const correctness

11

Supposons que j'ai un type appelable comme ceci:

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

Notez que mutable_callablepossède un non-const operator()qui modifie une variable membre .....

Supposons maintenant que je crée un std::functionde mon type:

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

Maintenant, je peux le faire:

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

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

Maintenant , pour autant que je peux dire std::functions operator()est constcomme par: https://en.cppreference.com/w/cpp/utility/functional/function/operator ()

Donc, mon instinct est que vous ne devriez pas pouvoir faire ça .....

Mais en regardant ensuite: https://en.cppreference.com/w/cpp/utility/functional/function/function

Cela ne semble pas imposer de contraintes quant au fait que le type appelable ait ou non une constante operator()......

Donc ma question est la suivante: j'ai raison de supposer que std::function<int()> const&c'est essentiellement la même chose que std::function<int()>&c'est qu'il n'y a pas réellement de différence entre le comportement des deux ...... et si c'est le cas pourquoi n'est-ce pas constcorrect?

DarthRubik
la source
@MaxLanghof No ..... std::functiona l'équivalent d'un a struct a{ std::any x; };dedans .....
DarthRubik
Voici un petit extrait des éléments internes de l' std::functionimplémentation MSVC : i.stack.imgur.com/eNenN.pngusing _Ptrt = _Func_base<_Ret, _Types...>. Je me repose mon cas.
Max Langhof

Réponses:

3

Cela se résume à la même chose que struct A { int* x; };, où dans un, const A a;vous pouvez modifier la valeur de *(a.x)(mais pas où elle pointe). Il existe un niveau d'indirection std::function(à partir de l'effacement de type) à travers lequel constne se propage pas.

Et non, ce std::function<int()> const& fn'est pas inutile. Dans un, std::function<int()>& fvous seriez en mesure d'affecter un foncteur différent f, ce que vous ne pouvez pas faire dans le constcas.

Max Langhof
la source
Yup ..... cela fait beaucoup de sens ..... toujours confus au premier coup d'œil
DarthRubik
Je pense que c'est un défaut de conception. Cette indirection devrait être un détail d'implémentation transparent pour l'utilisateur, et la constance pourrait être propagée à l'aide d'une métaprogrammation.
Igor R.
@IgorR. Oui, la constance pourrait se propager. std::vectorfait cela, std::unique_ptrnon. Je pense qu'il std::functionne s'agit pas vraiment d'exprimer des invariants de l'état du foncteur. Peut-être pourrions-nous réutiliser des types de fonctions abominables (c. std::function<int() const>-à- d. ) Pour distinguer?
Max Langhof
unique_ptrne doit pas propager la constance, contrairement au pointeur normal. Et std::function<int() const>ne compilerait pas.
Igor R.
@IgorR. Je connais. Mon point était que certaines parties de la bibliothèque standard le font et d'autres non. La catégorie std::functionà laquelle je dois entrer n'est pas claire pour moi. Et std::function<int() const>c'était une hypothèse - bien sûr, il ne compile pas maintenant, mais satisferait-il par exemple l'OP ici si cela pouvait être rendu valide, exprimant "ne peut être affecté que des foncteurs avec un operator() const(ou des apatrides)"? (même si en coulisses ce serait assez atroce, en raison de l'utilisation de types de fonctions abominables)?
Max Langhof