Question

Je veux que ce code soit possible.

template<typename K, typename T, typename Comparer>
class AVLTree
{
   ...
   void foo() {
       ...
       int res = Comparer::compare(key1, key2);
       ...
   }
   ...
};

Plus précisément, je veux forcer la classe pour avoir une Comparer fonction static int compare(K key1, K key2). Je pensais à l'aide de dérivation, mais n'a pas pu trouver des idées qui peuvent travailler avec des modèles.

Merci.

Était-ce utile?

La solution

Vous ne pouvez pas. Mais si l'on utilise la fonction et le ne pas Comparer, votre compilation échouera et ce qui est plus ou moins ce que vous voulez arriver. Et oui, comme d'autres ont indiqué que vous voulez appeler statique comme statique.

Autres conseils

Avez-vous essayé de faire:

   int res = Comparer::compare(key1, key2);

Dans les fonctions statiques C + peut être appelé de deux façons:

object.static_method(); // use dot operator

classname::static_method(); // use scope resolution operator

déjà mentionné que cela ne compilera pas si Comparer ne ont la fonction de membre requise.

Si vous êtes plus cependant inquiet au sujet des messages d'erreur concis, utilisez quelque chose comme cette pour détecter si la classe a une fonction de membre requise et le combiner avec quelque chose comme < a href = "http://www.boost.org/doc/libs/1_41_0/doc/html/boost_staticassert.html" rel = "nofollow noreferrer"> Boost.StaticAssert :

template<typename K, typename T, typename Comparer>
class AVLTree
{
    BOOST_STATIC_ASSERT(HasCompareMethod<Comparer>::has);
    //...
};

Il devrait être Comparer::Compare, non? (Puisque vous appelez une fonction statique sur un type).

Votre classe devrait Comparer être défini comme suit:

template<typename K>
class Comparer
{
public:
    static bool Compare(K key, K key)
    {
        return true;
    }
};

Je comprends que vous êtes à la recherche d'un meilleur message d'erreur dans le cas où le paramètre de modèle ne correspond pas aux exigences du corps de modèle. la langue ne dispose pas d'un mécanisme spécial pour cette construction, mais les gens se rapprochent à l'aide de bibliothèques. voir Boost Concept Vérifier

L'approche lâche d'avoir une affirmation de compilation autour est de prendre l'adresse de comparer et :: Comparer l'assigner à une variable déclarée comme int (K, K) * fonct.

Cette affectation ne fonctionnera que si elle est une fonction statique, mais ne fonctionnera pas si elle est une fonction membre.

Je suis tout cela contribue, mais je prendrais l'approche de l'utilisation des idiomes boost comme cela est roulé à la main, pour ainsi dire.

Voici une approche plus idiomatiques et générique:

template<typename K, typename T>
class AVLTree
{
   ...
   template <typename Comparer>
   void foo(Comparer cmp) {
       ...
       int res = cmp(key1, key2);
       ...
   }
   ...
};

Comparer ne doit pas être d'un type qui définit une méthode de Compare statique. Il devrait être un type qui peut être appelé avec la syntaxe d'appel de fonction. Cela vous permet d'utiliser des pointeurs de fonction des objets de fonction, et il vous permet de réutiliser les déjà définis dans les comparateurs de la bibliothèque standard, ou à peu près tout autre nonbanal application C ++. Il vous permet d'utiliser lambdas quand ils sont ajoutés dans C ++ 0x.

Comme pour forcer Comparer à se comporter comme prévu? La ligne int res = cmp(key1, key2); assure déjà. Si vous essayez de passer un type qui ne peut pas être appelé de cette façon, vous obtenez une erreur de compilation.

La même chose était le cas dans votre code d'origine. Si vous avez passé un type qui n'a pas de méthode Compare statique, vous obtiendrez une erreur de compilation. Ainsi, votre code d'origine déjà résolu le problème.

Comme nous l'avons souligné, vous ne pouvez pas forcer Comparez avoir un compare membre statique. Si votre comparateur ne met pas en œuvre, vous obtenez juste une erreur du compilateur.

Si vous implémentez AVLTree comme cela, il serait plus élégant de déclarer Comparer comme modèle paramètre template :

template <typename K>
class DefaultComparer
{
public:
    static bool compare(K k1, K k2)
    { return k1 == k2; }
};

template <typename K>
class MyComparer : public DefaultComparer<K>
{
public:
    static bool compare(K k1, K k2)
    { return k1 <= k2; }
};

template <typename K>
class InvalidComparer
{
public:
    static bool bar(K k1, K k2)
    { return k1 != k2; }
    // Doesn't implement compare()
};

// Compare is a template template paramenter with default template argument
// DefaultComparer
template <typename K, template <typename K> class Comparer = DefaultComparer>
class AVLTree
{
    K k1, k2;
public:
    AVLTree() : k1(0), k2(0) { } // ctor
    bool foo();
};

// Definiton of AVLTree::foo()
template <typename K, template <typename K> class Comparer>
bool AVLTree<K, Comparer>::foo()
{
    return Comparer<K>::compare(k1, k2);
}

int main(int argc, char *argv[])
{
    // Without template template parameters you 
    // would have to use AVLTree<int, DefaultComparer<int> >
    AVLTree<int> avltree;

    // instead of AVLTree<int, MyCompare<int> >
    AVLTree<int, MyComparer> avltree2;

    // Calling foo() will generate a compile error. 
    // But if you never call avltree3.foo() this will compile!
    AVLTree<int, InvalidComparer> avltree3;

    avltree.foo(); // calls DefaultComparer::compare
    avltree2.foo(); // calls MyComparer::compare
    avltree3.foo(); // fails to compile
}

voir: http://codepad.org/OLhIPjed

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top