2015-11-24 198 views
1

我試圖指定一個模板類的功能,該功能只能在使用特定類型(KEY作爲std::string和VALUE作爲std::string)創建類的對象時使用。專門化模板成員函數

我的模板(Dictionary.h),簡化爲:

#ifndef QB_DICTIONARY_H 
#define QB_DICTIONARY_H 

#include <map> 
#include <string> 

namespace QB { 
    template<typename KEY, typename VALUE, typename COMPARE = std::less<KEY>> 
    class Dictionary { 
    public: 
     typedef typename std::map<KEY, VALUE, COMPARE>::iterator iterator; 
     typedef typename std::map<KEY, VALUE, COMPARE>::const_iterator const_iterator; 

     Dictionary() { 
     } 

     Dictionary(const std::map<KEY, VALUE, COMPARE> & value) { 
      this->value = value; 
     } 

     typename iterator begin() { 
      return value.begin(); 
     } 

     typename const_iterator begin() const { 
      return value.cbegin(); 
     } 

     typename iterator end() { 
      return value.end(); 
     } 

     typename const_iterator end() const { 
      return value.cend(); 
     } 

     // Trying to have the function work only when the template KEY and VALUE are of type std::string 
     const std::string implode<std::string, std::string>(const std::string & valueSeparator, const std::string & pairSeparator) const { 
      std::string result; 

      for (iterator i = begin(); i != end(); i++) { 
       if (i != begin()) { 
        result += pairSeparator; 
       } 

       result += iterator->first; 
       result += valueSeparator; 
       result += iterator->second; 
      } 

      return result; 
     } 

    private: 
     std::map<KEY, VALUE, COMPARE> value; 
    }; 
} 

#endif 

的破滅功能是一個我試圖實現。試圖編譯在這上面的結果:

1>d:\cloud storage\onedrive\projects\qb\qb\dictionary.h(115): error C2143: syntax error: missing ';' before '<' 
1> d:\cloud storage\onedrive\projects\qb\qb\dictionary.h(133): note: see reference to class template instantiation 'QB::Dictionary<KEY,VALUE,COMPARE>' being compiled 
1>d:\cloud storage\onedrive\projects\qb\qb\dictionary.h(115): error C2334: unexpected token(s) preceding '{'; skipping apparent function body 

我不知道我應該如何實現這一點。任何提示?


編輯:

我遇到了一些新問題,同時嘗試@ TartanLlama的答案。

我當前的代碼如下(不相關的部分排除在外): Dictionary.h

#ifndef QB_DICTIONARY_H 
#define QB_DICTIONARY_H 

#include <map> 
#include <string> 
#include <type_traits> 

namespace QB { 
    template<typename KEY, typename VALUE, typename COMPARE = std::less<KEY>> 
    class Dictionary { 
    public: 
     // ... 

     const std::string implode(const std::string &, const std::string &) const; 

     // ... 
    }; 

    template<typename K=KEY, typename V=VALUE, typename COMPARE = std::less<KEY>> 
    std::enable_if_t<std::is_same<std::string, K>{} && std::is_same<std::string, V>{}, const std::string> Dictionary<K, V, COMPARE>::implode(const std::string & valueSeparator, const std::string & pairSeparator) const { 
     // ... 
    } 
} 

#endif 

回答

1

您試圖明確專用implode,但它不是模板。

你可以使用SFINAE只啓用該功能,如果KEYVALUEstd::string

template <typename K=KEY, typename V=VALUE> 
std::enable_if_t<std::is_same<std::string, K>{} && 
       std::is_same<std::string, V>{}, 
       const std::string> 
implode(const std::string & valueSeparator, 
     const std::string & pairSeparator) const { 
    //... 
} 

你可以使用static_assert發出一個錯誤,如果函數被實例化的錯誤Dictionary專業化:

implode(const std::string & valueSeparator, 
     const std::string & pairSeparator) const { 
    static_assert(std::is_same<std::string, K>{} && 
        std::is_same<std::string, V>{}, 
        "KEY and VALUE must be std::string"); 
    //... 
} 
+0

這可能會來派上用場。它工作,所以我upvoted它,但coincoin的答案是更加優雅。不管怎樣,謝謝! – Qub1

+0

@ Qub1要注意的一件事是,如果你做錯了什麼,這些解決方案會給你一個編譯時錯誤,而coincoin的解決方案會給你一個鏈接時錯誤。 – TartanLlama

+0

我注意到了。這可能會使調試變得困難。是否有可能將兩種解決方案結合起來? – Qub1

1

您可以通過顯式實例的方法成員像這樣的類定義之外的專業:

template<> std::string QB::Dictionary<std::string, std::string>::implode(const std::string & valueSeparator, const std::string & pairSeparator) const { 
    std::string result; 

    for (const_iterator i = begin(); i != end(); i++) { 
     if (i != begin()) { 
      result += pairSeparator; 
     } 

     result += i->first; 
     result += valueSeparator; 
     result += i->second; 
    } 

    return result; 
} 

Live Code

注意,我哈已修復其他錯誤(無需在返回方法類型中添加類型名稱,使用const_iterator ...)

+1

謝謝,完美的作品:) – Qub1