2010-10-12 61 views
3

我以为我想模板功能专业化,但this stackoverflow article让我觉得我应该真的通过做功能重载。但是,我只是没有看到我如何能够实现我想要的。类模板专业化对功能重载

我已经能够实现类模板专业化的目标,但我不喜欢这样的事实,我有这么多的模板类和专门的类之间复制代码。

我所拥有的是一个类,其中包含用于排序类对象的两个键。此外,我想创建一个方法match(),如果字符串的起始部分匹配(即,由于两个字符串的前三个字符都是'aaa'),所以字符串将返回true(即,“aaa”将匹配“aaa:zzz”),但是整数,短裤等只有匹配完全匹配时才会匹配(即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

这是为了让typdefs如:

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

但我发现,功能专业化似乎想把所有的模板参数中指定。


编辑10/12/10

PigBen的建议解决了这个问题的说明。

后来我意识到我的问题有点不同,有两个模板参数,我试图只专注于一个。这真的改变了这个问题。它看起来像我 需要做一些像完成here(这是类似于詹姆斯麦克奈利斯建议的解决方案)。

+0

专业化的这些功能看起来与一般形式的功能相同。我错过了什么吗? – 2010-10-12 01:27:33

+0

Bah!你是对的。假设专业化的match()函数是不同的。我编辑了代码以正确反映这一点。抱歉。 – 2010-10-12 03:36:07

+0

击败了我。 +1 – wheaties 2010-10-12 17:16:03

回答

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 
} 
+0

我能够得到这个解决方案来处理我说过的问题。但后来我意识到我过分简化了我的问题。我实际上有两个模板参数,我不能让这个解决方案使用两个参数。您能否阅读我的更新并提供更多见解? – 2010-10-12 17:15:19

+1

不幸的是,你不能部分地专注于模板功能。但是,有一个雄辩的解决方案使用重载的朋友功能。看到我更新的答案。请注意,它们不必是朋友功能。但是我这样做是为了使函数可以模拟成员函数,将传递的参数视为* this。 – 2010-10-12 20:45:27

2

如果唯一不同的是match函数,那么让类使用函数指针调用匹配函数,而不是在类内部添加匹配函数(类似于C的qsort函数)。将你的两个匹配例程写成独立的函数,并为你的类的每个实例分配一个指向适当匹配函数的指针。无可否认,这是一个C-ISH解决问题的方法,但它应该起作用。

+0

我不会说这是如此的c。。 C++ map,set和其他函数允许比较函数作为参数来做同样的事情。我认为这是一个很好的方法。 – JoshD 2010-10-12 01:23:42

+0

这是一个有趣的方法,但是我遇到的问题是它要求编码员特别将匹配功能与模板实例相关联。或者我错过了你的建议? – 2010-10-12 15:59:54

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); 
}