2010-11-07 4 views
1

Comment devrais-je m'assurer que les classes nécessaires comme params à ma classe modélisée auront une certaine interface? Je sais que l'one-way est de faire dans la classe Interface pure virtuelle mais je voudrais l'éviter. Y a-t-il un autre moyen de le faire? Je voudrais éviter tout ce qui est pas standardComment imposer une interface?

//Example 
    template<class SomePolicy> 
    class My 
    { 
void fnc()const 
{ 
SomePolicy::mustHaveThisInterface();//<--here I have to have 
// this interface in orded to work 

} 
    }; 
+0

Qu'entendez-vous exactement par interface? Voulez-vous juste être sûr que la classe définit une fonction 'void mustHaveThisInterface()'?Ou est-il nécessaire de surcharger le 'virtual must 'mustHaveThisInterface()' défini dans une classe de base prédéfinie? – jalf

+0

@jalf le premier jalf;) –

+2

alors la réponse est "juste essayer de compiler le code". Le compilateur le rejettera si la fonction n'est pas définie. :) – jalf

Répondre

2

Une solution simple est d'avoir une fonction fictive qui valide l'exigence. Exemple:

class Interface {}; 

    // Basically a no-op, but has to compile. 
template<typename I, typename T> 
void require() 
{ 
    T * t = 0; I * i = t; 
} 

template<class SomePolicy> 
class My 
{ 
    void fnc() const 
    { 
      // won't compile unless `SomePolicy` inherits `Interface`. 
     require<Interface, SomePolicy>(); 
    } 
}; 

Notez que, puisque c'est un modèle, My<T>::fnc() ne sera pas compilé sauf si elle est appelée, ce qui signifie que votre directive validation require<I,T>() doit être placé quelque part importante (par exemple le constructeur, ou au début de chaque fonction où SomePolicy doit hériter Interface.) Le nombre de contrôles que vous placez dépend de votre niveau de paranoïa. : Performance Performance Note: étant donné que la vérification équivaut à un no-op, tout compilateur décent l'optimisera de sorte qu'il ne coûtera rien en temps d'exécution ou en mémoire. Le compilateur est toujours obligé de le rendre compiile, ce qui signifie qu'il ne peut pas passer le test à la compilation.

+0

Caron J'aime beaucoup cette approche. Juste pour m'assurer que j'ai bien compris - la vérification est basée sur le fait que le pointeur de la classe Base peut être assigné à un pointeur sur une classe dérivée, n'est-ce pas? –

+0

Vous le comprenez correctement, mais c'est l'inverse, le pointeur vers la classe dérivée peut être assigné au pointeur d'une classe de base! –

+0

oui vous avez raison –

1

Vous devriez pouvoir utiliser type_traits et SFINAE pour garantir que SomePolicy hérite d'une interface.

template<typename T> class My { 
    typedef typename std::enable_if< 
     std::is_base< 
      T, 
      some_interface 
     >::value, 
     bool 
    >::type __traits__impl; // Won't compile if T does not inherit from interface 
}; 
+0

@DeadMG pourriez-vous s'il vous plaît donner un exemple ou peut-être un lien avec l'exemple? Je vous remercie. –

+0

@DeadMG est-ce ce dont parle Andree? –

+0

@There: Non. Je vais poster un exemple. – Puppy

4

La question est ce que vous entendez par "interface". Si vous voulez simplement que la classe contienne certaines méthodes, utilisez simplement ces méthodes. Si la classe donnée au modèle ne les a pas, vous obtiendrez une erreur de compilation si vous essayez d'instancier le modèle avec cette classe.

Il ne compilera que si toutes les méthodes que vous essayez d'utiliser existent réellement.

+1

Je suis d'accord avec sth. Il y a quelque temps, un collègue m'a présenté à Eiffel où il était possible dans le langage d'inclure des contraintes qu'un paramètre de type template hérite d'un type spécifié. Bien que cela puisse sembler utile, cela supprime l'une des principales libertés des modèles. Que vous pouvez utiliser n'importe quel type approprié indépendamment de la façon dont il correspond à votre hiérarchie d'héritage. En insistant sur le fait que le paramètre de type hérité d'une classe particulière peut vous mordre plus tard lorsque vous souhaitez utiliser une classe que vous ne pouvez pas contrôler pour ce paramètre. –

1

Boost a une bibliothèque appelée Concept Check pour cette utilisation. Il peut être utilisé pour garantir que tout paramètre de type à un modèle possède les fonctionnalités minimales requises pour l'opération de ce modèle. Il est livré avec des contrôles pour toutes les interfaces de la bibliothèque standard, et vous montre comment écrire le vôtre pour les interfaces que vous avez inventées.

+0

presque comme stroustrup;), merci pour votre réponse. J'ai oublié d'ajouter dans mon post original que je voudrais éviter tout ce qui n'est pas standard. Je vais mettre à jour mon message. –

2

Selon ce que vous entendez par « interface », le code affiché peut déjà faire le travail:

//Example 
template<class SomePolicy> 
class My 
{ 
    void fnc() const 
    { 
     SomePolicy::mustHaveThisInterface(); 
     // this interface in orded to work 
    } 
}; 

ce code ne parviendra pas à compiler si mustHaveThisInterface() ne définit pas la classe SomePolicy. Donc, vous êtes déjà garanti que la classe de politique a l'interface correcte.

Si au contraire, vous voulez vous assurer que SomePolicy dérive d'une certaine classe d'interface qui définit une mustHaveThisInterface virtuelle, vous pouvez utiliser std::is_base_of de l'en-tête type_traits ajouté dans TR1 (et précédemment disponible de Boost):

std::is_base_of<MyInterface, SomePolicy>::value sera vrai si et seulement si SomePolicy est dérivé de MyInterface.

4

Stroustrup a écrit sur les solutions pour cela. Vérifiez here et here.

+0

+1 pour avoir référencé le mec qui a tout commencé. Ça ne va pas beaucoup mieux que ça. :) –

Questions connexes