Параметр шаблона C ++ Force - PullRequest
       10

Параметр шаблона C ++ Force

0 голосов
/ 26 декабря 2009

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

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). Я думал об использовании деривации, но не смог найти идей, которые могли бы работать с шаблонами.

Спасибо.

Ответы [ 8 ]

4 голосов
/ 26 декабря 2009

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

4 голосов
/ 26 декабря 2009

Вы пробовали делать:

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

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

object.static_method(); // use dot operator

classname::static_method(); // use scope resolution operator
2 голосов
/ 26 декабря 2009

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

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

template<typename K, typename T, typename Comparer>
class AVLTree
{
    BOOST_STATIC_ASSERT(HasCompareMethod<Comparer>::has);
    //...
};
1 голос
/ 27 декабря 2009

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

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

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

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

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

1 голос
/ 26 декабря 2009

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

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

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

1 голос
/ 26 декабря 2009

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

1 голос
/ 26 декабря 2009

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

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

template<typename K>
class Comparer
{
public:
    static bool Compare(K key, K key)
    {
        return true;
    }
};
0 голосов
/ 26 декабря 2009

Как уже указывалось, вы не можете заставить 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...