En C ++ 14, les conteneurs associatifs semblent avoir changé depuis C ++ 11 - [associative.reqmts] / 13 dit:
Les modèles de fonction membre
find
,count
,lower_bound
,upper_bound
etequal_range
ne participent pas à la résolution de surcharge sauf si le typeCompare::is_transparent
existe.
Quel est le but de rendre un comparateur "transparent"?
C ++ 14 fournit également des modèles de bibliothèques comme celui-ci:
template <class T = void> struct less {
constexpr bool operator()(const T& x, const T& y) const;
typedef T first_argument_type;
typedef T second_argument_type;
typedef bool result_type;
};
template <> struct less<void> {
template <class T, class U> auto operator()(T&& t, U&& u) const
-> decltype(std::forward<T>(t) < std::forward<U>(u));
typedef *unspecified* is_transparent;
};
Ainsi, par exemple, std::set<T, std::less<T>>
n'aurait pas de comparateur transparent, mais en std::set<T, std::less<>>
aurait un.
Quel problème cela résout-il et cela change-t-il le fonctionnement des conteneurs standard? Par exemple, les paramètres du modèle de std::set
sont encore Key, Compare = std::less<Key>, ...
, plus le jeu par défaut perdre ses find
, count
, des membres?
Réponses:
Voir la réponse de Dietmar et la réponse de remyabel .
Non, pas par défaut.
Les nouvelles surcharges de modèle de fonction membre de
find
etc. vous permettent d'utiliser un type comparable à la clé du conteneur, au lieu d'utiliser le type de clé lui-même. Voir N3465 par Joaquín Mª López Muñoz pour la justification et une proposition détaillée et soigneusement écrite pour ajouter cette fonctionnalité.Lors de la réunion de Bristol, le LWG a convenu que la fonction de recherche hétérogène était utile et souhaitable, mais nous ne pouvions pas être sûrs que la proposition de Joaquín serait sûre dans tous les cas. La proposition N3465 aurait causé de sérieux problèmes pour certains programmes (voir la section Impact sur le code existant ). Joaquín a préparé un projet de proposition mis à jour avec des implémentations alternatives avec différents compromis, ce qui était très utile pour aider le LWG à comprendre les avantages et les inconvénients, mais ils risquaient tous de casser certains programmes d'une manière ou d'une autre, il n'y avait donc pas de consensus pour ajouter la fonctionnalité. Nous avons décidé que même s'il ne serait pas sûr d'ajouter la fonctionnalité sans condition, ce serait sûr si elle était désactivée par défaut et uniquement "opt-in".
La principale différence de la proposition N3657 (qui était une révision de dernière minute par moi-même et STL basée sur N3465 et un projet ultérieur non publié par Joaquín) était d'ajouter le
is_transparent
type comme protocole qui peut être utilisé pour opter pour la nouvelle fonctionnalité.Si vous n'utilisez pas de "foncteur transparent" (c'est-à-dire celui qui définit un
is_transparent
type) alors les conteneurs se comportent comme ils l'ont toujours fait, et c'est toujours la valeur par défaut.Si vous choisissez d'utiliser
std::less<>
(ce qui est nouveau pour C ++ 14) ou un autre type de "foncteur transparent", vous obtenez la nouvelle fonctionnalité.L'utilisation
std::less<>
est facile avec les modèles d'alias:Le nom
is_transparent
vient du N3421 de STL qui a ajouté les "opérateurs diamantés" au C ++ 14. Un "foncteur transparent" est celui qui accepte tous les types d'arguments (qui ne doivent pas nécessairement être identiques) et transmet simplement ces arguments à un autre opérateur. Un tel foncteur se trouve être exactement ce que vous voulez pour une recherche hétérogène dans des conteneurs associatifs, de sorte que le type ais_transparent
été ajouté à tous les opérateurs de diamant et utilisé comme type de balise pour indiquer que la nouvelle fonctionnalité doit être activée dans les conteneurs associatifs. Techniquement, les conteneurs n'ont pas besoin d'un "foncteur transparent", juste un qui prend en charge l'appeler avec des types hétérogènes (par exemple, lepointer_comp
type dans https://stackoverflow.com/a/18940595/981959 n'est pas transparent selon la définition de STL,pointer_comp::is_transparent
permet de l'utiliser pour résoudre le problème). Si vous ne jamais votre recherche dansstd::set<T, C>
des clés de typeT
ouint
alorsC
besoin que d'être appelable avec des arguments de typeT
etint
(dans un ordre), il n'a pas besoin d'être vraiment transparent. Nous avons utilisé ce nom en partie parce que nous ne pouvions pas trouver un meilleur nom (j'aurais préféréis_polymorphic
parce que ces foncteurs utilisent le polymorphisme statique, mais il existe déjà unstd::is_polymorphic
trait de type qui fait référence au polymorphisme dynamique).la source
<>
dans la proposition liée, mais cette proposition n'a pas été introduite<>
- c'est la syntaxe existante pour une liste de paramètres de modèle vide. Les "foncteurs d'opérateur diamant" seraient un peu moins déroutants.En C ++ 11 il n'y a pas des modèles de membres
find()
,lower_bound()
etc. C'est, rien ne se perd par ce changement. Les modèles de membre ont été introduits avec n3657 pour permettre l'utilisation de clés hétérogènes avec les conteneurs associatifs. Je ne vois aucun exemple concret où cela soit utile à l'exception de l'exemple qui est bon et mauvais!L'
is_transparent
utilisation est destinée à éviter les conversions indésirables. Si les modèles de membre n'étaient pas soumis à des contraintes, le code existant peut passer directement par des objets qui auraient été convertis sans les modèles de membre. L'exemple de cas d'utilisation de n3657 consiste à localiser un objet dans un enstd::set<std::string>
utilisant un littéral de chaîne: avec la définition C ++ 11, unstd::string
objet est construit lors du passage d'un littéral de chaîne à la fonction membre correspondante. Avec la modification, il est possible d'utiliser directement la chaîne littérale. Si l'objet de la fonction de comparaison sous-jacent est implémenté exclusivement en termes destd::string
cela est mauvais car maintenant unstd::string
serait créé pour chaque comparaison. D'autre part, si l'objet de la fonction de comparaison sous-jacent peut prendre unstd::string
et une chaîne littérale, qui peut éviter la construction d'un objet temporaire.Le
is_transparent
type imbriqué dans l'objet fonction de comparaison fournit un moyen de spécifier si la fonction membre basée sur un modèle doit être utilisée: si l'objet fonction de comparaison peut traiter des arguments hétérogènes, il définit ce type pour indiquer qu'il peut traiter efficacement différents arguments. Par exemple, les nouveaux objets de fonction d'opérateur délèguent simplementoperator<()
et prétendent être transparents. Cela, au moins, fonctionne pourstd::string
qui a surchargé moins que les opérateurs prenantchar const*
comme argument. Étant donné que ces objets de fonction sont également nouveaux, même s'ils ne font pas la bonne chose (c'est-à-dire nécessitent une conversion pour un certain type), il ne s'agirait au moins pas d'un changement silencieux entraînant une dégradation des performances.la source
is_transparent
est défini dans l'objet fonction de comparaison selon 23.2.4 [associative.reqmts] paragraphe 13. Les objets fonction de comparaison par défaut sontstd::less<Key>
conformes à 23.4.2 [associative.map.syn] et 23.4. 3 [associative.set.syn]. Selon 20.10.5 [comparaison] paragraphe 4, le modèle général pourstd::less<...>
ne définit pas un type imbriquéis_transparent
mais lastd::less<void>
spécialisation le fait. Autrement dit, non, vous n'obtenez pas d'opérateur transparent par défaut.is_transparent
?Ce qui suit est toutes les pâtes à copier de n3657 .
Pour citer Yakk ,
et n3657,
n3421 fournit un exemple de «fonctions d'opérateur transparentes» .
Le code complet est ici .
la source
std::set<std::string>
réellement du "passagechar const *
", ou avez-vous besoin de faire unstd::set<std::string, std::less<>>
?With the change proposed by N3465 the std::set::find() function would be an unconstrained template which would pass the const char* through to the comparator function, std::less<std::string>, which would construct a std::string temporary for every comparison. The LWG considered this performance problem to be a serious issue.
Stephan T Lavavej parle des problèmes où le compilateur continue de créer des temporaires, et comment sa proposition de foncteurs d'opérateurs transparents résoudra cela en c ++ 1y
GoingNative 2013 - N'aidez pas le compilateur (à peu près à l'heure)
la source