Pourquoi est std::function et non l'égalité comparable?
Cette question s'applique aussi à boost::function
et std::tr1::function
.
std::function
n'est pas l'égalité comparable:
#include <functional>
void foo() { }
int main() {
std::function<void()> f(foo), g(foo);
bool are_equal(f == g); //Error: f and g are not equality comparable
}
En C++11, le operator==
et operator!=
surcharges n'existent tout simplement pas. Dans un début de C++11 projet de, les surcharges ont été déclarés comme étant supprimés avec le commentaire (N3092 §20.8.14.2):
//deleted overloads close possible hole in the type system
Il ne dit pas ce que la possibilité "d'un trou dans le système de type" est. Dans TR1 et Boost, les surcharges sont déclarés mais non définis. Le TR1 spécification commentaires (N1836 §3.7.2.6):
Ces fonctions de membre doivent être laissés dans le vague.
[Remarque: la boolean-comme la conversion ouvre une faille qui fonction à deux instances peuvent être comparés par
==
ou!=
. Ces undefinedvoid
opérateurs à proximité de la faille et de veiller à une erreur de compilation. —la note de fin de]
Ma compréhension de la "faille" est que si nous avons un bool
fonction de conversion, la conversion peut être utilisé dans la comparaison d'égalité (et dans d'autres circonstances):
struct S {
operator bool() { return false; }
};
int main() {
S a, b;
bool are_equal(a == b); //Uses operator bool on a and b! Oh no!
}
J'étais sous l'impression que le coffre-bool idiome en C++03 et l'utilisation d'une conversion explicite de la fonction en C++11 a été utilisé pour éviter cette "lacune." De stimuler et de TR1 à la fois utiliser le coffre-bool idiome dans function
et C++11 fait le bool
fonction de conversion explicite.
Comme un exemple d'une classe qui a les deux, std::shared_ptr
à la fois explicitement de bool
de fonctions de conversion et d'égalité comparable.
Pourquoi est std::function
pas l'égalité comparable? Qu'est-ce que la possibilité "d'un trou dans le type de système?" Comment est-il différent de std::shared_ptr
?
- Notez que vous pouvez demander pour
* a.target< ftor_type >() == * b.target< ftor_type >()
s'ils pointent vers l'égalité comparable à la foncteurs. Bien que ce soit un peu capricieux (l'objet sous-jacent va pas être implicitement converti dans le type demandé), il ne précise pas exactement dont la sémantique de comparaison sont utilisés.
Vous devez vous connecter pour publier un commentaire.
std::function
est un wrapper pour arbitraire appelable types, afin de mettre en œuvre l'égalité de comparaison à tous, vous auriez à exiger que tous les appelable types de l'égalité-comparible, placer un fardeau sur quelqu'mise en œuvre d'une fonction d'objet. Même alors, vous obtiendrez un concept étroit de l'égalité, comme l'équivalent des fonctions serait de comparer l'inégalité (par exemple) si elles ont été construites par la liaison des arguments dans un ordre différent. Je crois qu'il est impossible de tester l'équivalence dans le cas général.Je suppose que cela signifie qu'il est plus facile de supprimer les opérateurs, et soyez certains que leur utilisation ne donnera jamais le code est valide, que pour prouver il n'y a pas de possibilité indésirables des conversions implicites dans certains jusque-là inconnues des cas de coin.
std::shared_ptr
a bien défini l'égalité sémantique; deux pointeurs sont égaux si et seulement si ils sont tous les deux vides, ou les deux non-vide et pointant vers le même objet.J'ai peut-être tort, mais je pense que l'égalité de
std::function
objets est, malheureusement, n'est pas soluble dans le sens générique. Par exemple:sont
f1
etf2
l'égalité? Ce que si j'ajoute un nombre arbitraire d'objets de fonction qui enroulez simplement les uns les autres de diverses manières qui finalement se résume à un appel àf
... toujours égale?function
peut décider de remplacer l'objet sous-jacent avec un autre fonctionnellement identique à l'objet. Votre proposition serait de restreindre cette capacité. En outre,std::function
aura de multiples implémentations de sorte que vous auriez à être très prudent dans la spécification de son comportement. (I. e. comment est-ADL du travail?)T::operator=
(pas de ADL) ou vous attendez-vous la recherche def.__obj == g.__obj
pour réussir?Je pense que la raison principale est que si elle l'était, il ne pouvait pas être utilisés avec de non égalité de types comparables, même si la comparaison d'égalité n'est jamais effectuée.
I. e. le code qui effectue la comparaison doit être instancié précoce, au moment où un objet appelable est stocké dans
std::function
, par exemple dans l'un des constructeurs ou des opérateurs d'affectation.Une telle limitation serait grandement réduire la portée de l'application, et, évidemment, de ne pas être acceptable pour un "à des fins générales fonction polymorphe wrapper".
Il est important de noter qu'il est possible de comparer un
boost::function
avec un objet appelable (mais pas avec un autreboost::function
)C'est possible, parce que la fonction qui effectue une telle comparaison est instancié à un point de comparaison, sur la base des types d'opérande.
En outre,
std::function
a uncible
modèle de fonction de membre, qui peut être utilisé pour effectuer la comparaison similaire. En faitboost::function
's les opérateurs de comparaison sont mis en œuvre en termes decible
de la fonction membre.Donc, il n'y a pas d'obstacles techniques qui bloquent la mise en œuvre de
function_comparable
.Parmi les réponses, il est commun "impossible en général" modèle:
Je suis complètement en désaccord avec ceci: il n'est pas le travail de
std::function
pour effectuer la comparaison elle-même; son travail est juste pour rediriger demande à la comparaison d'objets sous-jacents, c'est tout.Si le sous-jacent type d'objet ne définit pas de la comparaison, il aura une erreur de compilation; en tout cas,
std::function
n'est pas nécessaire d'en déduire un algorithme de comparaison.Si le sous-jacent type d'objet définit la comparaison, mais qui fonctionne à tort, ou a quelques-uns inhabituelle sémantique, il n'est pas le problème de
std::function
elle-même, mais c'est le problème de la type sous-jacent.Il est possible de mettre en œuvre
function_comparable
basé surstd::function
.Ici est une preuve-de-concept:
Il y a une belle propriété -
function_comparable
peut être comparé à desstd::function
trop.Par exemple, disons que nous avons vecteur de
std::function
s, et nous voulons donner aux utilisateursregister_callback
etunregister_callback
fonctions. L'utilisation defunction_comparable
est requise uniquement pour lesunregister_callback
paramètre:Démonstration en direct à Ideone
Le code Source de la démo:
De sortie est:
P. S. Il semble que, avec l'aide de
std::type_index
, il est possible de mettre en place quelque chose de similaire àfunction_comparable
classe, qui prend également en charge la commande (c'est à direstd::less
) ou même de hachage. Non seulement la commande entre les différents types, mais aussi de la commande au sein d'un même type (ce qui nécessite la prise en charge de types, commeLessThanComparable
).Selon http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#1240:
En C++11, l'supprimé fonctions sont considérées comme superflu avec l'introduction de la conversion explicite des opérateurs, donc ils vont probablement être retiré pour le C++11.
Pour laquelle vous ne pouvez pas comparer
std::function
des objets, c'est probablement parce qu'ils peuvent éventuellement tenir statique/globale des fonctions, des fonctions de membre du, foncteurs, etc, et pour ce fairestd::function
"efface" quelques informations sur le type sous-jacent. Mise en œuvre d'un opérateur d'égalité ne serait probablement pas possible à cause de cela.En fait, vous pouvez comparer les cibles. Il peut travailler dépend de ce que vous voulez de comparaison.
Ici le code de l'inégalité, mais vous pouvez voir comment cela fonctionne:
Ups, il n'est valable que depuis C++11.
target<T>
renvoie uneT*
qui n'est pas null IFFT
correspond à la fonction sous-jacente pointeur/foncteur type/bind type d'expression. Vous appelez ça commefunction<void(void)>::target<function<void(void)>>
. Le type sous-jacent defunction<void(void)>
estvoid(void)
, pasfunction<void(void)>
. Les deux pointeurs obtenus (ptr1
etptr2
) sont à la fois toujoursnullptr
, etnullptr < nullptr
est toujoursfalse
, qui est ce qui empêche la deuxième insertion. La première insertion, ne réussit qu'à cause de laset
est vide, donc il n'y a rien à comparer.set
n'acceptera un maximum d'unfunction
.Pourquoi ne pas essayer quelque chose comme ce qui suit, cela fonctionne bien pour le test des modèles.
le moins qui puisse être fait est si std::fonction enregistre l'adresse de la fonction utilisée pour la liaison à une chaîne et utilisé comparaison de chaînes de caractères à la place.