4 votes

utiliser std::bind en lambda avec std::unique_ptr

// By const l-value reference
auto func2 = std::bind([](const std::unique_ptr< std::vector<int> >& pw) // fine
{
    std::cout << "size of vector2: " << pw->size() << std::endl;
}, std::make_unique<std::vector<int>>(22, 1));

//By non-const l-value reference
auto func3 = std::bind([](std::unique_ptr< std::vector<int> >& pw) // fine
{
    std::cout << "size of vector3: " << pw->size() << std::endl;
}, std::make_unique<std::vector<int>>(22, 1));

// By Value
auto func4 = std::bind([](std::unique_ptr< std::vector<int> > pw) // error
{
    std::cout << "size of vector4: " << pw->size() << std::endl;
}, std::make_unique<std::vector<int>>(22, 1));
func4(); // without this line, compilation is fine. The VS generates error for the calling of the bind object.
// By r-value reference
auto func5 = std::bind([](std::unique_ptr< std::vector<int> >&& pw) // error
{
    std::cout << "size of vector5: " << pw->size() << std::endl;
}, std::make_unique<std::vector<int>>(22, 1));
func5(); // without this line, compilation is fine.

Pourquoi func4 et func5 ne compilent pas ?

4voto

O'Neil Points 3278

func4 produit une erreur car le paramètre de la lambda est passé par valeur. Mais std::unique_ptr n'est pas copiable.

func5 est plus complexe, nous pouvons lire dans la documentation std::bind :

Étant donné un objet g obtenu à partir d'un appel antérieur à bind, lorsqu'il est invoqué dans une expression d'appel de fonction g(u1, u2, ... uM) une invocation de l'objet stocké a lieu, comme si par std::invoke(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN)) , donde fd est une valeur de type std::decay_t<F> les valeurs et les types des arguments liés v1 , v2 , ..., vN sont déterminés comme indiqué ci-dessous.
...
l'argument stocké ordinaire arg est passé à l'objet invocable comme argument lvalue : l'argument vn dans l'appel std::invoke ci-dessus est simplement arg et le type correspondant Vn es T cv & , donde cv est le même cv-qualification que celui de g .

Par conséquent, même si std::make_unique<std::vector<int>>(22, 1) est une valeur r, une valeur l est donnée à la lambda, ce qui n'est pas compatible avec la valeur r attendue.
Cela peut aussi expliquer pourquoi func3 fonctionne bien.

2voto

Yakk Points 31636

bind renvoie un objet fonction qui peut être invoqué plus d'une fois.

Il prend ses arguments et les stocke dans un tuple (ou équivalent). Elle invoque ensuite le premier argument avec le reste. Ceci est similaire à std::invoke à partir de C++17.

Pour vos deux cas d'échec, vous ne pouviez pas appeler le lambda plus d'une fois. Vous obtenez donc une erreur lorsque vous l'appelez une fois, car bind suppose que vous voulez être en mesure de l'appeler à nouveau . Faire autre chose serait de la folie, car il ne peut pas savoir que vous ne l'appellerez plus jamais dans le cadre de son operator() .

Logiquement, ces appels debe échouer. La norme exige également qu'ils échouent, car la norme, dans ce cas, se comporte logiquement.


auto funcA =
  [pw=std::make_unique<std::vector<int>>(22,1)]
  {
    std::cout << "size of vector2: " << pw->size() << std::endl;
  };

auto funcB =
  [pw=std::make_unique<std::vector<int>>(22,1)]() mutable
  {
    std::cout << "size of vector2: " << pw->size() << std::endl;
  };

Voici deux lambdas différents qui font à peu près ce que votre code a fait. Au lieu de bind et pass, on capture simplement.

En funcA nous avons un const unique_ptr en funcB nous avons un non const unique_ptr . Dans le second, nous pourrions sortir du ptr unique ; dans le premier, nous ne pouvons pas.

std::bind a été écrit avant que les lambdas n'existent en C++, et c'est rarement une meilleure idée que d'utiliser un lambda. Les déficiences des lambdas ont été en grande partie supprimées par le C++14, et il existe très peu de situations où l'utilisation de bind au lieu d'un lambda est une bonne idée.

std::bind génère des messages d'erreur cryptiques et a un comportement étrange dans un certain nombre de cas particuliers, comme le fait de transmettre le résultat de bind à un autre bind .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X