Comment avoir le type de template déduit dans les arguments std :: function avec lambda?

J’ai un boost :: variante et je voudrais exécuter un foncteur seulement si la variante est d’un type spécial, alors j’ai créé cette fonction

template void if_init(Variant& opt_variant, std::function functor){ if(auto* ptr = boost::get(&opt_variant)){ functor(*ptr); } } 

Cela fonctionne bien, mais j’aimerais que le type T soit déduit, pour pouvoir écrire que:

 if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; }); 

Mais le type n’est pas déduit:

 type_inference.cpp:19:5: error: no matching function for call to 'if_init' if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; }); ^~~~~~~ type_inference.cpp:10:6: note: candidate template ignored: failed template argument deduction void if_init(Variant& opt_variant, std::function functor){ 

Si j’écris:

 if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; }); 

Ça marche bien.

Existe-t-il un moyen de déduire le type T? Je voudrais taper T une seule fois. Ici, le type est court, mais dans le cas réel, il existe des types longs.

J’utilise CLang 3.2.

Voici le scénario de test complet (le premier appel ne comstack pas le second):

 #include  #include  #include  typedef boost::variant Test; template void if_init(Variant& opt_variant, std::function functor){ if(auto* ptr = boost::get(&opt_variant)){ functor(*ptr); } } int main(){ Test b = 1.44; if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; }); if_init(b, [](int var){ std::cout << "I'm int and set" << std::endl; }); return 0; } 

Je vous recommande de penser à std::function tant que conteneur de tout foncteur conforme à Sig tant que signature – et pouvant être remplacé à tout moment. Cette fonctionnalité est très pratique pour, par exemple, std::vector> car un tel conteneur peut alors contenir des foncteurs de types différents .

Dans votre cas, parce que vous ne vous souciez que d’un seul foncteur, vous n’avez vraiment pas besoin des fonctionnalités de std::function . En tant que tel, je vous recommande de déclarer votre modèle de fonction comme suit:

 template void if_init(Variant& opt_variant, Functor functor); 

Si vous craignez que cela ne communique pas que Functor doit se conformer à une signature void(T) , veuillez noter que std::function n’applique pas cela non plus: bien que, de toute évidence, vous obtiendrez une erreur de compilation, elle n’est pas une belle. Il est prévu de le modifier (et peut-être que votre implémentation l’a également), mais il a été remplacé par un type d’erreur différent. Ce n’est toujours pas utile pour votre cas.

Personnellement, je me sers d’alias de modèles ( dans la liste des parameters de modèles ) pour documenter et appliquer ce à quoi un foncteur doit se conformer. Cela finit par ressembler à:

 // Documents that eg long l = std::forward(functor)(42.) // should be a valid expression -- a functor that returns int would // also be accepted. // Triggers a hard-error (typically a static_assert with a nice message) // on violation. template>...> R foo(Functor functor); // Documents that this function template only participates in overload resolution // if the functor conforms to the signature. // Does not sortinggger a hard-error (necessary by design); if everything goes right // then another overload should be picked up -- otherwise an error of the kind // 'no matching overload found' is produced template>...> R bar(Functor functor); 

En ce qui concerne votre question exacte , les règles de C ++ ne permettent pas de déduire un paramètre de modèle dans votre cas. Ce n’est vraiment pas un «problème» facile à résoudre, s’il en est un. Vous pouvez trouver plus d’informations à ce sujet.