J'ai trouvé que lvalue
les fermetures lambda peuvent toujours être passées en tant que rvalue
paramè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 fn1
fermeture après le retour de la fonction?
fn1
est implicitement converti en unstd::function
infoo(fn1)
. Cette fonction temporaire est alors une valeur r.std::function
être déduits d'un lambda". Votre programme n'essaie pas de déduire les arguments du modèle destd::function
, il n'y a donc pas de problème avec la conversion implicite.std::function
a 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èlestd::function
ne peut pas être déduite du type lambda. (Par exemple, ilstd::function<void()>
peut être construit à partir[](){return 5;}
même s'il a un type de retour non nul.Réponses:
L'invocation
foo
requiert une instance destd::function<void()>
cette liaison à une référence rvalue .std::function<void()>
peut être construit à partir de tout objet appelable compatible avec lavoid()
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::function
instance:Ensuite, l'
function
instance temporaire est liée à la référence rvalue.Comme précédemment, car il a été copié dans une
std::function
instance. La fermeture d'origine n'est pas affectée.la source
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::function
art. Cela signifie qu'un temporairestd::function
est matérialisé par la copiefn1
. 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
fn1
tout ce qui se passe n'est pas affectéfoo
.la source
fn1
est apatride, car il ne capture rien.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 destd::function
. Le résultat de la conversion est une valeur pr et peut donc être lié à la référence rvalue.la source