2017-01-25 3 views
4

Quelle est la différence entre l'utilisation d'un nom de fonction avec et sans une perluète? J'ai remarqué qu'ils se comportent différemment lorsqu'ils sont liés à un paramètre de modèle:Pourquoi le pointeur sur la fonction ne peut pas se lier à la référence lvalue, alors que la fonction peut le faire?

void foo(); 
template <typename F> void bind(F&); 
bind(foo); // OK 
bind(&foo); // Error 

Pourquoi est-ce ainsi? Quel est le type déduit dans ces cas?

+2

Même raison que pour int int; void bind (int &); ': Vous pouvez dire' bind (a) 'mais pas' bind (& a) '. –

Répondre

2

&foo est un anonyme temporaire de sorte qu'il ne peut pas se lier à une référence non const.

Si vous aviez écrit

template <typename F> void bind(const F&); 

alors compilation aurait été couronnée de succès.


foo est pas temporaire anonyme si la liaison à une référence est autorisée.

4

Notez que intégré operator& renverra un prvalue de type T*. Donc, &foo retournera un pointeur de fonction avec le type void (*)(), qui est une prvalue et ne peut pas être lié à lvalue référence à non-const; c'est exactement ce que bind() attend en tant que paramètre, puis il échoue.

Pour bind(foo), modèle pamareter F sera déduit que le type de fonction exactement (à savoir void()), le type d'argument de bind sera void(&)(), donc il fonctionne.

Vous pourriez penser que foo et &foo devraient avoir le même effet en raison de la décroissance de la fonction-à-pointeur. Mais notez que le paramètre bind() est déclaré en tant que passage par référence. Alors pour le bind(foo), la désintégration fonction-à-pointeur ne se produit pas, c'est pourquoi le type d'argument est déduit comme référence à la fonction. D'autre part, pour bind(&foo), operator& est appelée explicitement pour renvoyer un pointeur de fonction prvalue, qui ne peut pas être passé à bind().

Si le paramètre est déclaré comme valeur de transfert, la désintégration fonction-à-pointeur se produit, alors bind(foo) et bind(&foo) auraient le même effet et les deux fonctionneraient correctement.

void foo(); 
template <typename F> void bind(F); 
bind(foo); // OK, F=void(*)() 
bind(&foo); // same as above