Y a-t-il un moyen, probablement à l'aide de modèles, de macros ou d'une combinaison des deux, que je peux appliquer génériquement une fonction à différentes classes d'objets, mais faites-leur de répondre de différentes manières si elles n'ont pas de fonction spécifique?
Je souhaite spécifiquement appliquer une fonction qui émettra la taille de l'objet (c.-à-d. Le nombre d'objets dans une collection) si l'objet a cette fonction mais émettra un simple remplacement (tel que "N / A") si l'objet ne le fait pas. IE P>
NO_OF_ELEMENTS( mySTLMap ) -----> [ calls mySTLMap.size() to give ] ------> 10 NO_OF_ELEMENTS( myNoSizeObj ) --> [ applies compile time logic to give ] -> "N/A"
6 Réponses :
Vous pouvez faire quelque chose comme essentiellement, la mise en œuvre la plus générique est toujours renvoyée -1 ou "na" mais pour le vecteur et les cartes, il retournera la taille. Comme le plus général correspond toujours, il n'y a jamais une panne de temps de construction p> p>
De ce que je comprends, vous voulez avoir un test générique pour voir si une classe a une fonction de certaines membres. Cela peut être accompli en C ++ en utilisant Sfinae . En C ++ 11, il est assez simple, car vous pouvez utiliser si vous utilisez c ++ 03, il est un peu plus difficile en raison du manque de bien sûr cela utilise dans les deux cas la signature de la méthode Bien sûr, cela retournera true si déclinger code>:
déclinger code>, vous devez donc abuser
Tailleof code> à la place: p>
boost.enable_if < / code>, qui pourrait être une dépendance indésirable (et inutile). Toutefois, l'écriture
activer_if code> vous est morte simple: p>
test (int) code> est uniquement visible, si
u code> a une méthode code> de taille code>, car sinon évaluant soit le
déclinger code> ou la taille
de code> (selon sur quelle version que vous utilisez) échouera, qui supprimera ensuite la méthode de la considération (en raison de
sfinae code>. Les longues expressions
std :: déclval (). Taille (), Void (), std :: true_type () code> est un abus d'opérateur de virgule C ++, qui retournera la dernière expression de la liste séparée par des virgules. Cela garantit donc que le type est appelé
std :: true_type code> pour la variante C ++ 11 (et la taille
de code> évalue
int code> pour la variante C ++ 03). Le
void () code > Au milieu n'est là que là-bas pour s'assurer qu'il n'y a pas d'étranges surcharges de l'opérateur de la virgule interférant avec l'évaluation. P>
t code> h En tant que méthode code> Taille CODE> appelable sans arguments, mais ne donne aucune garantie sur la valeur de retour. Je suppose que tu veux probablement détecter que ces méthodes qui ne retournent pas nulle. Cela peut être facilement accompli avec une légère modification du test
(int) code> méthode: p>
Intéressant ... mais quel est le void () code> pour?
@Matthieum.: Le void () code> n'est pas strictement nécessaire. Cependant, il est là de veiller à ce qu'aucune chose étrange ne se passe avec des opérateurs de virgules surchargés (peu probable dans ce cas, mais c'est la manière générale que j'utilise pour vérifier toutes les méthodes qui, donc je pensais que je le garderais).
Je pensais brièvement que cela pourrait être le cas, mais cela semble être plus semblable à ce que c'était un croft oublié lorsque vous avez ajouté true_type code> :) comme pour aller le
déclenlette code> way, Ça fait Les choses si faciles pour les fonctions, qu'il est plus facile de définir des traits tels que
consexpr code> ou simplement des traits de contournement et utilisez-le directement, voir ma réponse :)
Ceci peut être fait en utilisant une technique appelée sfinae . Dans votre cas spécifique, vous pouvez mettre en œuvre que l'utilisation de Boost.Concept Check < / a>. Vous devriez écrire votre propre concept pour vérifier une taille code> -method. Sinon, vous pouvez utiliser un concept existant tel que < Code> conteneur code> , qui, entre autres, nécessite une taille
code> -method. p>
Je suis surpris que cette réponse n'a pas eu de top vote. Sfinae est la voie à suivre ici, imho.
@Azza: Même si je n'aime pas le "tu peux faire quelque chose comme" code> "style des réponses, la plupart des réponses présentent ici des pratiques Sfinae ...
Vous pouvez essayer quelque chose comme:
#include <iostream> #include <vector> template<typename T> struct has_size { typedef char one; typedef struct { char a[2]; } two; template<typename Sig> struct select { }; template<typename U> static one check (U*, select<char (&)[((&U::size)!=0)]>* const = 0); static two check (...); static bool const value = sizeof (one) == sizeof (check (static_cast<T*> (0))); }; struct A{ }; int main ( ) { std::cout << has_size<int>::value << "\n"; std::cout << has_size<A>::value << "\n"; std::cout << has_size<std::vector<int>>::value << "\n"; }
vous y allez. strong> remplacer std :: cout code> avec la sortie de votre sympathique.
template <typename T>
class has_size
{
template <typename C> static char test( typeof(&C::size) ) ;
template <typename C> static long test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
template<bool T>
struct outputter
{
template< typename C >
static void output( const C& object )
{
std::cout << object.size();
}
};
template<>
struct outputter<false>
{
template< typename C >
static void output( const C& )
{
std::cout << "N/A";
}
};
template<typename T>
void NO_OF_ELEMENTS( const T &object )
{
outputter< has_size<T>::value >::output( object );
}
Cela ne fonctionnera pas. objet.size () code> provoquera une défaillance. Vous devez déléguer l'impression à une structure Sfinae'd.
@Matthieuum. Oui! J'ai négligé ça. Merci. Corrigé maintenant.
Il y avait une discussion sur les capacités de Il est facile de concevoir un trait avec si facile en fait que le trait perd la majeure partie de sa valeur: p> En action : p> consexpr code> il y a plusieurs fois. Il est temps de l'utiliser, je pense :)
consexpr code> et
déclinger code>: p>
Je peux voir l'utilisation de void () code> dans la réponse de grizzly, mais ici? Semble superflu, car il n'y aura pas de deuxième paramètre à un opérateur de virgule "possible" de toute façon. Une gauche-over?
Je ne suis pas sûr que c'est la meilleure façon d'écrire le trait. Comparé à l'approche "commune" de la capituler dans une structure, vous n'avez évité que l'écriture de la structure autour des méthodes et la mise en place de la valeur de résultat dans une énumération ou un consexpr bool code>. D'autre part,
has_size code> a une signature moins désierable de cette manière imo. Mêmes gores pour
print_size code>.
@Xeo: the void () code> in
print_size code> est utilisé pour lui donner une déclaration de retour de
Void code> au lieu de
déclnder (déclval
@Grizzly: Je vois ça différent. C'est certainement nouveau, alors je m'attends à une certaine résistance. J'ai donné quelques raisons pendant que je pense que les traits pourraient être déplacés vers des fonctions ici . Il y a quelques années, j'aurais adopté vos cours, mais j'essaie maintenant d'explorer C ++ 11 possibilités, en particulier pour réduire l'encombrement et obtenir de nouvelles fonctionnalités.
Notez que vous pouvez réduire encore plus l'encombrement en utilisant le type de retour de suivi: auto print_size (t const & t) -> déclinger (T.Size (), void ()) code>.
Duplicaté possible: Stackoverflow.com/Questtions/257288/...
@AlessandroCezzato: Avec C ++ 11 frappant à la porte, il y a de nouvelles opportunités qui n'ont pas été explorées dans la réponse liée.
Merci pour toutes les réponses et conseils. Malheureusement, je ne peux pas utiliser C ++ 11 ou booster dans ma solution en raison des limitations des clients, qui est dommage. Néanmoins, avec les informations que vous avez toutes fournies, j'ai pu obtenir cela aller et l'étendre pour fournir une fonction de diffusion de la taille () ou de "" à l'aide d'une classe de modèle privé et intégré, partiellement Spécialisé pour la condition «vraie». Je suis maintenant très heureux !! Merci à tous!