Специализация шаблонов классов и перегрузка функций - PullRequest
3 голосов
/ 12 октября 2010

Я думал, что хочу специализовать функции шаблонов, но эта статья о стековом потоке заставляет меня думать, что я действительно должен делать перегрузку функций. Однако я просто не вижу, как я могу достичь того, чего хочу.

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

У меня есть класс с двумя ключами, которые используются для сортировки объектов класса. Более того, я хочу создать метод match(), который для строки вернет true, если начальная часть строки совпадает (то есть «aaa» будет соответствовать «aaa: zzz», потому что первые три символа обеих строк - «aaa») ), но целые, шорты и т. д. будут совпадать только в случае их точного соответствия (т. е. 1 == 1).

Я получил это для работы, используя специализацию класса, как показано ниже:

template <class    KEY2_TYPE>
class policy_key_c
{
public:

    policy_key_c (int          _key1,
                  KEY2_TYPE    _key2) :
        key1(_key1),
        key2(_key2)
        {};


    virtual ~policy_key_c(void) {};


    virtual std::string strIdx (void) const {
        // combine key1 and key2 into an index to be returned.
    }


    //
    // operator <
    //
    virtual bool operator< (const policy_key_c    &b) const {
        return (operator<(&b));
    }


    virtual bool operator< (const policy_key_c    *p) const {

        // if the primary key is less then it's less, don't check 2ndary
        if (key1 < p->key1) {
            return (true);
        }


        // if not less then it's >=, check if equal, if it's not equal then it
        // must be greater
        if (!(key1 == p->key1)) {
            return (false);
        }

        // its equal to, so check the secondary key
        return (key2 < p->key2);
    }



    //
    // operator ==
    //
    virtual bool operator== (const policy_key_c    &b) const {
        return(operator==(&b));
    }


    virtual bool operator== (const policy_key_c    *p) const {

        // if the primary key isn't equal, then we're not equal
        if ((key1 != p->key1)) {
            return (false);
        }

        // primary key is equal, so now check the secondary key. 
        return (key2 == p->key2);
    }


    //
    // match
    //
    virtual bool match (const policy_key_c    &b) const {
        return(operator==(&b));
    }


    virtual bool match (const policy_key_c    *p) const {
        return (operator==(p));
    }


protected:

    int          key1;    // The primary key
    KEY2_TYPE    key2;    // The secondary key.
   // ... other class data members ....
};




// Now specialize the template for a string as the secondary key
//
template <>
class policy_key_c<std::string>
{
public:
    //
    // .... all the other functions
    //

    //
    // match
    //
    virtual bool match (const policy_key_c    &b) const {
        return(operator==(&b));
    }


    virtual bool match (const policy_key_c    *p) const {
        // do a prefix string match rather than a complete match.
        return (key2.substr(0, p->key2.lenght()) == p->key2);
    }


protected:

    int            key1;    // The primary key
    std::string    key2;    // The secondary key.
   // ... other class data members ....
};

Мне не нравится это решение, потому что там так много копируемого кода. Единственное, что ведет себя по-другому - это функция соответствия. Когда key2 представляет собой int, short или char соответствует, ведет себя как == wherease, если key2 является std :: string, я хочу, чтобы оно соответствовало префиксу.

Есть ли "более эффективный" способ сделать это? Может ли это быть сделано с перегрузкой функции соответствия? Если это может быть перегружено, я был бы признателен за идеи о том, как. Я пробовал несколько вариантов перегрузки и с треском провалился.

Заранее спасибо.


Изменить 10/12/10

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

template <int KEY1_VAL, class KEY2_TYPE> class policy_key_c

Это должно было разрешить typedefs, такие как:

typedef    policy_key_c<1, int>           int_policy;
typedef    policy_key_c<2, std::string>   str_policy;

Но я обнаружил, что специализация функции, по-видимому, требует указания всех параметров шаблона.


Изменить 10/12/10

Предложение PigBen решило проблему, как указано.

Позже я понял, что моя проблема немного отличается, с двумя параметрами шаблона, и я пытался специализироваться только на одном. Это действительно меняет вопрос. И, похоже, я нужно сделать что-то вроде готового здесь (что аналогично предлагаемому решению Джеймса МакНеллиса).

Ответы [ 3 ]

3 голосов
/ 12 октября 2010

Если единственное, что ведет себя по-разному, это отдельная функция, то вам не нужно специализировать весь класс, вы можете просто специализировать эту функцию. Я не уверен, есть ли синтаксис, чтобы сделать это, когда функция определена в теле класса, но если вы определяете функцию извне, то вы можете сделать это так:

template <class T>
class X
{
    void f();
};

template <class T>
void X<T>::f()
{
    // general code
}

template<>
void X<std::string>::f()
{
    // specialized code
}

Для нескольких параметров шаблона

template<int K, typename T> class X;
template<int K, typename T> void friend_func(X<K,T> &);

template<int K, typename T>
class X
{
public:
    void class_func();
    friend void friend_func<>(X &);
};

template<int K, typename T>
void X<K,T>::class_func()
{
    friend_func(*this);
}

template<int K, typename T>
void friend_func(X<K,T> & x)
{
    // non specialized version
}

template<int K>
void friend_func(X<K,std::string> & x)
{
    // specialized version
}
2 голосов
/ 12 октября 2010

Если отличается только функция match, то пусть класс вызывает функцию match, используя указатель функции, вместо добавления функции match внутри класса (аналогично функции C qsort). Напишите две подпрограммы сопоставления как независимые функции и присвойте каждому экземпляру вашего класса указатель на соответствующую функцию сопоставления. Это, по общему признанию, подход к проблеме, но он должен работать.

1 голос
/ 12 октября 2010

Вы можете иметь делегат шаблона функции match() для функции-члена шаблона класса. Тогда вы можете специализировать шаблон класса:

// primary template for general-purpose matching
template <typename T>
struct match_impl
{
    static bool match(const T& x) { return true; }
};

// specialization for std::string matching
template <>
struct match_impl<std::string>
{
    static bool match(const std::string& x) { return true; }
};

template <typename T>
bool match(const T& x)
{
    return match_impl<T>::match(x);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...