15 votes

C++11 std::function et transmission parfaite

Pourquoi la définition de std::function<>::operator() dans le standard C++ est :

R operator()(ArgTypes...) const;

et non

R operator()(ArgTypes&&...) const;

?

On pourrait penser que pour faire suivre correctement les paramètres, il faut utiliser le && et ensuite le std::forward<ArgTypes>... dans le corps de la fonction lors du transfert de l'appel ?

J'ai partiellement réimplémenté std::function pour tester cela et j'ai découvert que si j'utilise le &&, j'obtiens "cannot bind 'xxx' lvalue to 'xxx&&'" de g++ lorsque j'essaie plus tard de passer des paramètres par valeur à operator(). Je pensais avoir suffisamment bien saisi les concepts de rvalue/forwarding, mais je n'arrive toujours pas à comprendre ce point. Qu'est-ce qui m'échappe ?

18voto

Xeo Points 69818

Le transfert parfait ne fonctionne que lorsque la fonction elle-même (dans le cas présent operator() ) est modélisé et les arguments du modèle sont déduits. Pour les std::function , vous obtenez le operator() des types d'arguments des paramètres du modèle de la classe lui-même, ce qui signifie qu'ils ne seront jamais déduits d'aucun argument.

Toute l'astuce de la transmission parfaite réside dans la déduction de l'argument du modèle, qui, avec l'effondrement de la référence, est la raison d'être de la transmission parfaite.

Je me contenterai d'un lien pratique vers mon autre réponse concernant std::forward ici, où j'explique comment le forwarding parfait (et les std::forward ) fonctionne.

Il convient de noter que std::function 's operator() n'a pas besoin d'une transmission parfaite, puisque c'est l'utilisateur lui-même qui décide des paramètres. C'est également la raison pour laquelle vous ne pouvez pas simplement ajouter && à operator() ; prenons l'exemple suivant :

void foo(int){}

int main(){
  // assume 'std::function' uses 'ArgTypes&&...' in 'operator()'
  std::function<void(int)> f(foo);
  // 'f's 'operator()' will be instantiated as
  // 'void operator()(int&&)'
  // which will only accept rvalues
  int i = 5;
  f(i); // error
  f(5); // OK, '5' is an rvalue
}

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