à l'aide de SFINAE pour la classe template de la spécialisation
supposons que j'ai ces déclarations
template<typename T> class User;
template<typename T> class Data;
et souhaitez mettre en œuvre User<>
pour T = Data<some_type>
et de toute classe dérivée de Data<some_type>
mais aussi d'autres spécialités définies par ailleurs.
Si je n'ai pas encore de la déclaration de la classe de modèle User<>
, je pourrais simplement
template<typename T,
typename A= typename std::enable_if<is_Data<T>::value>::type>
class User { /*...*/ };
où
template<template<typename> data>> struct is_Data
{ static const bool value = /* some magic here (not the question) */; };
Cependant, ce qui a deux paramètres du modèle et donc des affrontements avec la déclaration précédente, où User<>
est déclarée avec un seul paramètre du modèle. Est-il autre chose que je peux faire?
(Note
template<typename T,
typename A= typename std::enable_if<is_Data<T>::value>::type>
class User<T> { /*...*/ };
ne fonctionne pas (modèle par défaut arguments ne peuvent pas être utilisés dans des spécialisations),
ni ne
template<typename T> class User<Data<T>> { /*...*/ };
qu'il n'autorise pas les types dérivés de Data<>
, ni ne
template<typename T>
class User<typename std::enable_if<is_Data<T>::value,T>::type>
{ /*...*/ };
depuis paramètre de modèle T
n'est pas utilisé dans la spécialisation partielle.)
- SFINAE peut être appliqué à choisir le modèle de spécialisations, voir en.cppreference.com/w/cpp/types/enable_if
- De sorte qu'il peut! J'ai appris quelque chose.
- Je ne pense pas que je comprends pourquoi les
static_assert
version ne fonctionnera pas. Soins à élaborer? - ce n'était pas un code correct, de toute façon (n'a pas à spécialiser l'original modèle de classe; retiré maintenant).
- Juste pour clarifier: Vous voulez être en mesure de démarrent des instances
User<>
pour toutData<>
ou sous-classe, mais pas pour n'importe quel autre type? DevraitUser<int>
ne parviennent pas à compiler? - Oui exactement (à moins que quelqu'un d'autre quelque part déclaré une spécialisation des
User<int>
). - Dans ce cas, pourquoi s'embêter avec une spécialisation partielle à tous? Ne pouvez-vous pas utiliser un statique affirmer dans le commerce non spécialisé version?
- N je veux avoir d'autres spécialisations partielles, par exemple
User<some type dervied from OtherData<0>>
(avectemplate<int> struct OtherData
). - Le problème est que vous ne pouvez pas changer d'Utilisateur, ou vous êtes à la recherche d'un moyen d'éviter cela. Et si vous êtes à la recherche d'un moyen de l'éviter, mais il est possible de le changer, tant que c'est quelque chose qui n'a pas à casser votre code est-il acceptable?
- Notez que l'utilisation de
std::enable_if
pour ce genre de SFINAE est un peu rond-point. À l'aide detypename = std::true_type
que la valeur par défaut paramètre, vous pouvez écrire partielle des spécifications qui correspond à<T, typename is_foo<T>::type>
en supposantis_foo
est par exemple un UnaryTypeTrait dans le sens de la Norme (l'un des traits de<type_traits>
comme ça). - merci pour cette!
Vous devez vous connecter pour publier un commentaire.
Puisque vous avez dit que vous étiez toujours en attente d'une meilleure réponse, voici mon prendre sur elle. Il n'est pas parfait, mais je pense qu'il vous permet de vous autant que possible à l'aide de SFINAE et partielle de spécialisations. (Je suppose que les Concepts fournira un ensemble complet et solution élégante, mais nous allons devoir attendre un peu plus longtemps pour que.)
La solution repose sur une fonctionnalité d'alias modèles qui a été spécifié que récemment, dans la norme des documents de travail après la dernière version de C++14, mais a été pris en charge par des implémentations pour un certain temps. Pertinentes libellé dans le projet de N4527 [14.5.7p3] est:
Voici un exemple complet de mise en œuvre de cette idée:
L'exécution de l'impression:
Comme vous pouvez le voir, il y a une ride: la spécialisation partielle n'est pas sélectionné pour
DD
, et il ne peut pas être, parce que de la façon dont nous l'a déclaré. Alors, pourquoi ne pas simplement direet lui permettre de match
DD
ainsi? Cela fonctionne dans GCC, mais il est rejeté à juste titre par Clang et MSVC à cause de [14.5.5p8.3, 8.4] ([p8.3] peuvent disparaître dans le futur, comme c'est redondant - GTC 2033):User<enable_if_data<T>>
est équivalent àUser<T>
(modulo la substitution dans cet argument par défaut, qui est géré séparément, comme l'a expliqué la première citation ci-dessus), ainsi qu'un formulaire non valide partielle de la spécialisation. Malheureusement, correspondant à des choses commeDD
nécessiterait, en général, une spécialisation partielle argument de la formeT
- il n'y a pas d'autre forme qu'il peut avoir et toujours correspondre à chaque cas. Donc, je crains que nous pouvons dire avec certitude que cette pièce ne peut pas être résolu au sein de la compte tenu de ses contraintes. (Il y a Question centrale 1980, qui fait allusion à un possible avenir règles concernant l'utilisation du modèle des alias, mais je doute qu'ils vont faire de notre cas valable.)Tant que les classes dérivées de
Data<T>
sont eux-mêmes spécialisations de modèle, plus contraignant eux en utilisant la technique ci-dessus fonctionne, donc j'espère que ce sera de quelque utilité pour vous.Prise en charge du compilateur (c'est ce que j'ai testé, d'autres versions peuvent travailler en tant que bien):
-Wall -Wextra -std=c++11 -pedantic
- fonctionne comme décrit ci-dessus.enable_if_data<T>
, de sorte que peut être une solution temporaire./W4
, fonctionne comme décrit ci-dessus. Les anciennes versions n'aime pas ledecltype
dans l'argument par défaut, mais la technique elle-même fonctionne encore - de remplacer l'argument par défaut avec une autre façon d'exprimer la contrainte permet de travailler sur 2013 mise à Jour 4.SI l'original de la déclaration de
User<>
peut être adapté àensuite, nous pouvons trouver une solution (à la suite de Luc Danton commentaire, au lieu d'utiliser
std::enable_if
)Cependant, cette ne répond pas à la question d'origine, car il nécessite de changer la définition d'origine de
User
. Je suis toujours en attente d'une meilleure réponse. Cela pourrait être l'un que de façon concluante démontre qu'aucune autre solution n'est possible.template<typename T> class User<T, typename std::enable_if<is_Data<T>::value>::type> { ... };
... affichera un "edit".Que vous ne voulez à mettre en œuvre lorsqu'une seule condition est vraie, la solution la plus simple est d'utiliser un statique affirmation. Il ne nécessite pas de SFINAE, donne clairement une erreur de compilation si mal utilisés et la déclaration de
User<>
n'a pas besoin d'être adaptées:Voir aussi: Lors de l'utilisation de
static_assert
au lieu de SFINAE?. Lestatic_assert
est un c++11 construire, cependant, il existe de nombreuses solutions disponibles en pré-c++11 compilateurs, comme:Si la déclaration de
user<>
peut être changé et que vous souhaitez deux implémentations en fonction de la valeur deis_Data
, puis il y a aussi une solution qui n'utilise pas SFINAE:La statique des assertions vérifie uniquement si l'utilisateur n'a pas de spécifiez le modèle argument
D
de manière incorrecte. SiD
n'est pas explicitement spécifié, alors la statique des assertions peuvent être omis.Data<T>
(modifier la question de mentionner que).