81 votes

Contraintes de modèles C ++

En C #, nous pouvons définir un type générique qui impose des contraintes sur les types pouvant être utilisés comme paramètre générique. L'exemple suivant illustre l'utilisation de contraintes génériques:

 interface IFoo
{
}


class Foo<T> where T : IFoo
{
}

class Bar : IFoo
{
}

class Simpson
{
}

class Program
{
    static void Main(string[] args)
    {
        Foo<Bar> a = new Foo<Bar>();
        Foo<Simpson> b = new Foo<Simpson>(); // error CS0309
    }
}
 

Existe-t-il un moyen d'imposer des contraintes pour les paramètres de modèle en C ++?


C ++ 0x a un support natif pour cela, mais je parle du C ++ standard actuel.

77voto

Venemo Points 7213

Si vous utilisez C ++11, vous pouvez utiliser static_assert avec std::is_base_of à cette fin.

Par exemple,

 template<typename T>
class YourClass {

    YourClass() {
        // Compile-time check
        static_assert(std::is_base_of<BaseClass, T>::value, "type parameter of this class must derive from BaseClass");

        // ...
    }
}
 

44voto

Daniel Spiewak Points 30706

"Implicitement" est la bonne réponse. Les modèles de façon à créer un "duck typing" scénario, en raison de la façon dont ils sont calculés. Vous pouvez appeler toutes les fonctions que vous voulez sur un modèle de type de valeur, et la seule instanciations qui seront acceptés sont ceux pour lesquels cette méthode est définie. Par exemple:

template <class T>
int compute_length(T *value)
{
    return value->length();
}

Nous pouvons appeler cette méthode sur un pointeur vers n'importe quel type qui déclare l' length() méthode de retour d'un int. Ainsi:

string s = "test";
vector<int> vec;
int i = 0;

compute_length(&s);
compute_length(&vec);

...mais pas sur un pointeur sur un type qui ne veut pas déclarer length():

compute_length(&i);

Ce troisième exemple ne compilera pas.

Cela fonctionne parce que le C++ compile une nouvelle version de la templatized fonction (ou une classe) pour chaque instanciation. Qu'il effectue cette compilation, il fait un direct, presque macro-comme la substitution de l'instanciation du modèle dans le code avant la vérification de type. Si tout fonctionne encore avec ce modèle, puis la compilation produit et nous avons fini par arriver à un résultat. Si quelque chose tombe en panne (comme int* de ne pas déclarer length()), alors nous obtenons la redoutable six modèle de page erreur de compilation.

37voto

luke Points 16255

Comme quelqu'un l'a mentionné, C++0x est l'obtention de cette fonction dans la langue. Jusqu'alors, je vous recommande de Bjarne Stroustrup's suggestions pour le modèle de contraintes.

Edit: Boost a aussi une alternative de sa propre.

Editx2: il Semble bien que les concepts ont été supprimés à partir de C++0x.

18voto

Eclipse Points 27662

Vous pouvez mettre un type de garde sur IFoo qui ne fait rien, assurez-vous qu'il soit présent sur T dans Foo:

 class IFoo
{
public:
    typedef int IsDerivedFromIFoo;
};

template <typename T>
class Foo<T>
{
    typedef typename T::IsDerivedFromIFoo IFooGuard;
}
 

9voto

Nemanja Trifunovic Points 17239

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X