Вопрос

Я хочу, чтобы этот код был возможен.

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

В частности, я хочу заставить класс Comparer иметь static int compare(K key1, K key2) функция.Я думал об использовании деривации, но не смог найти идей, которые могли бы работать с шаблонами.

Спасибо.

Это было полезно?

Решение

Вы не можете.Но если вы используете эту функцию, а в Comparer ее нет, ваша компиляция завершится неудачей, и это более или менее то, что вы хотите.И да, как отмечали другие, вы хотите называть статику статической.

Другие советы

Вы пытались сделать:

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

В C++ статические функции можно вызывать двумя способами:

object.static_method(); // use dot operator

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

Майкл уже упоминалось что это не скомпилируется, если Comparer не имеет необходимой функции-члена.

Однако, если вас больше беспокоят краткие сообщения об ошибках, используйте что-то вроде этот чтобы определить, есть ли в классе необходимая функция-член, и объединить ее с чем-то вроде Boost.StaticAssert:

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

Это должно было быть Comparer::Compare, верно?(Поскольку вы вызываете статическую функцию для типа).

Ваш класс Comparer должен быть определен следующим образом:

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

Я понимаю, что вы ищете лучшее сообщение об ошибке, если параметр шаблона не соответствует требованиям тела шаблона.в языке нет специального встроенного механизма, но люди аппроксимируют его с помощью библиотек.видеть Проверка концепции повышения

Свободный подход к утверждению во время компиляции заключается в том, чтобы взять адрес Comparer::compare и присвоить его переменной, объявленной как int(K, K) *func.

Это назначение будет работать, если это статическая функция, но не будет работать, если это функция-член.

Я просто вношу свой вклад, но я бы выбрал подход, основанный на использовании идиом повышения, поскольку это, так сказать, вручную.

Вот более идиоматический и общий подход:

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

Компаратор не должен быть типом, определяющим статический Compare метод.Это должен быть тип, который можно вызвать с помощью синтаксиса вызова функции.Это позволяет вам использовать указатели функций функциональных объектов и повторно использовать компараторы, уже определенные в стандартной библиотеке или практически в любом другом нетривиальном приложении C++.Это позволяет вам использовать лямбды, когда они добавляются в C++0x.

Что касается принуждения Comparer вести себя так, как ожидалось?Линия int res = cmp(key1, key2); уже гарантирует это.Если вы попытаетесь передать тип, который нельзя вызвать таким образом, вы получите ошибку компиляции.

То же самое было и в исходном коде.Если вы передали тип, у которого не было статического Compare метод, вы получите ошибку компиляции.Итак, ваш исходный код уже решил проблему.

Как уже указывалось, вы не можете заставить Compare иметь статический член. compare.Если ваш компаратор этого не реализует, вы просто получите ошибку компилятора.

Если вы реализуете AVLTree вот так было бы элегантнее объявить Comparer как параметр шаблона шаблона:

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
}

видеть: http://codepad.org/OLhIPjed

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top