Les valeurs de fermeture lambda peuvent être passées en tant que paramètres de référence rvalue

18

J'ai trouvé que lvalueles fermetures lambda peuvent toujours être passées en tant que rvalueparamètres de fonction.

Voir la démonstration simple suivante.

#include <iostream>
#include <functional>

using namespace std;

void foo(std::function<void()>&& t)
{
}

int main()
{
    // Case 1: passing a `lvalue` closure
    auto fn1 = []{};
    foo(fn1);                          // works

    // Case 2: passing a `lvalue` function object
    std::function<void()> fn2 = []{};
    foo(fn2);                          // compile error

    return 0;
}

Le cas 2 est le comportement standard (je viens d'utiliser un std::functionà des fins de démonstration, mais tout autre type se comporterait de la même manière).

Comment et pourquoi fonctionne le cas 1? Quel est l'état de fn1fermeture après le retour de la fonction?

Sumudu
la source
5
Je suppose que c'est parce qu'il fn1est implicitement converti en un std::functionin foo(fn1). Cette fonction temporaire est alors une valeur r.
eike
@RichardCritten Je n'étais vraiment pas sûr, donc je n'ai pas posté de réponse. Je pense que maintenant il n'y a pas besoin d'un autre.
eike
1
@eike np Je ressens souvent la même chose, et yup de nombreuses réponses.
Richard Critten
2
@Sumudu La personne qui a posé la question vous a induit en erreur parce qu'elle ne savait pas ce qu'elle essayait de demander. Ce qu'ils voulaient demander était: "Pourquoi les arguments de modèle ne peuvent-ils pas std::functionêtre déduits d'un lambda". Votre programme n'essaie pas de déduire les arguments du modèle de std::function, il n'y a donc pas de problème avec la conversion implicite.
eerorika
1
Le titre de la question que vous avez liée est un peu trompeur. std::functiona un constructeur non explicite qui accepte les fermetures lambda, il y a donc une conversion implicite. Mais dans les circonstances de la question liée, l'instanciation du modèle std::functionne peut pas être déduite du type lambda. (Par exemple, il std::function<void()>peut être construit à partir [](){return 5;}même s'il a un type de retour non nul.
eike

Réponses:

8

Comment et pourquoi fonctionne le cas 1?

L'invocation foorequiert une instance de std::function<void()>cette liaison à une référence rvalue . std::function<void()>peut être construit à partir de tout objet appelable compatible avec la void()signature.

Tout d'abord, un std::function<void()>objet temporaire est construit à partir de []{}. Le constructeur utilisé est le # 5 ici , qui copie la fermeture dans l' std::functioninstance:

template< class F >
function( F f );

Initialise la cible avec std::move(f). Si fest un pointeur nul pour la fonction ou un pointeur nul pour le membre, *thissera vide après l'appel.

Ensuite, l' functioninstance temporaire est liée à la référence rvalue.


Quel est l'état de fermeture de fn1 après le retour de la fonction?

Comme précédemment, car il a été copié dans une std::functioninstance. La fermeture d'origine n'est pas affectée.

Vittorio Romeo
la source
8

Un lambda n'est pas un std::function. La référence ne se lie pas directement .

Le cas 1 fonctionne parce que les lambdas sont convertibles en std::functionart. Cela signifie qu'un temporaire std::functionest matérialisé par la copie fn1 . Ledit temporaire peut être lié à une référence rvalue, et donc l'argument correspond au paramètre.

Et la copie est également la raison pour laquelle fn1tout ce qui se passe n'est pas affecté foo.

Conteur - Unslander Monica
la source
5

Quel est l'état de fermeture de fn1 après le retour de la fonction?

fn1 est apatride, car il ne capture rien.

Comment et pourquoi fonctionne le cas 1?

Cela fonctionne parce que l'argument est de type différent de celui référencé par rvalue. En raison d'un type différent, les conversions implicites sont prises en compte. Puisque le lambda est Callable pour les arguments de ceci std::function, il est implicitement convertible en lui via le constructeur de conversion de modèle de std::function. Le résultat de la conversion est une valeur pr et peut donc être lié à la référence rvalue.

eerorika
la source