类模板专业化与函数重载

时间:2010-10-12 01:05:10

标签: c++ templates

我认为我想模板函数专门化,但this stackoverflow article让我觉得我应该通过函数重载来实现。但是,我只是没有看到如何实现我想要的目标。

我已经能够通过类模板专业化实现目标,但我不喜欢在模板类和专用类之间有如此多的复制代码的事实。

我所拥有的是一个类,其中包括两个用于对类对象进行排序的键。此外,我想创建一个方法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

这是为了允许typdef,例如:

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

但我发现功能专业化似乎需要指定所有模板参数。


编辑10/12/10

PigBen的建议解决了所述问题。

后来我意识到我的问题略有不同,有两个模板参数,我试图只专注于一个。这真的改变了这个问题。它看起来像我 我需要做像here这样的事情(类似于James McNellis建议的解决方案)。

3 个答案:

答案 0 :(得分:3)

如果唯一表现不同的是单个函数,那么您不必专门化整个类,您可以专门化该函数。我不确定当在类的主体中定义函数时是否有语法来执行此操作,但如果您在外部定义函数,那么您可以这样做:

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
}

答案 1 :(得分:2)

如果唯一不同的是match函数,那么让类使用函数指针调用匹配函数,而不是在类中添加匹配函数(类似于C的qsort功能)。将两个匹配例程写为独立函数,并为类的每个实例分配一个指向相应匹配函数的指针。诚然,这是解决问题的C-ish方法,但它应该可行。

答案 2 :(得分:1)

您可以将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);
}