【问题标题】:Can't get method template to specialize properly无法使方法模板正确专业化
【发布时间】:2013-12-16 00:15:03
【问题描述】:

我有一个模板类,它可以正常工作,但如果类型 T 是字符串,我需要重载插入方法。

template <class T> 
class hashtable{
 public:
    void insert(T item){
        /* Do Stuff */          
        };
    template<> void insert(string item){
        /* Do different stuff */
        };
}

这是抛出错误 C2912:显式特化; 'void hashtable::insert(std::string)' 不是函数模板的特化。

我不确定我做错了什么,或者我该如何解决这个问题。我所需要的只是一种根据 T 是否为字符串来以不同方式调用插入函数的方法。

【问题讨论】:

标签: c++ templates specialization


【解决方案1】:

您根本不需要添加template 字样。您只需重载模板函数。

class hashtable{
 public:
    template <typename T>
    void insert(T item){
        /* Do Stuff */          
    };

    void insert(string item){
        /* Do different stuff.
        Implementation can go to *.cpp file if necessary. 
        */
    };
};

但请注意,无论设计如何,当您尝试 insert 隐式可转换为 std::string 的类型时都会遇到麻烦,包括 const std::string &amp;const char*。信不信由你,在 C++03 中,std::string 甚至有来自int 的隐式构造函数!

这就是为什么人们通常更喜欢将哈希表类而不是函数模板化。

【讨论】:

    【解决方案2】:

    您需要在模板括号中指定专业化:

    template<class string> void insert(string item) ...
    

    模板 用于消除类特化中的所有参数。这里有一个这样的例子:

    http://www.cplusplus.com/doc/tutorial/templates/#template_specialization

    【讨论】:

      【解决方案3】:

      在类定义之外编写特化:

      template <typename T> class hashtable { /* ... */ };
      
      template <> void hashtable<std::string>::insert(std::string item)
      {
          // ...
      }
      

      【讨论】:

      • 以及cpp文件中的实现?
      • @polkadotcadaver:不,也在标题中。
      • 认为在这种情况下你可以把它分开,但我必须检查一下。
      【解决方案4】:

      我不确定这堂课的意义。 T 类型的类中有内部对象吗?如果没有,我会执行以下操作:

      class hashtable{
       public:
          template <typename T>
          void insert(T item){
              /* Do Stuff */          
              };
      
          template<>
          void insert(string item){
              /* Do different stuff */
              };
      }
      

      如果你在课堂上确实有 T 类型的东西,那么也许你正在寻找这个:

      template <typename T>
      class hashtable{
       public:
          template <typename P>
          void insert(P item){
              /* Do Stuff */          
              };
      
          template<>
          void insert(string item){
              /* Do different stuff */
              };
      }
      

      您需要详细说明您正在尝试做的事情。

      【讨论】:

      • 该类的其余部分是一个有效的哈希表,它只是在它是字符串类型的情况下分解,这就是我需要重载这个函数的原因。
      【解决方案5】:

      最简单的方法是标签分发/

      创建一个继承自 std::true_typestd::false_type 的特征类,具体取决于您要使用的实现。

      然后编写两个带有ture_typefalse_type 参数的impl 方法,如下所示:

       template<typename T> void insert(T&& t) { insert_impl(std::forward<T>(t), traits_test<T>() ); }
      
      template<typename T> void insert_impl(T t, std::true_type descriptive_name ){ code }
      template<typename T> void insert_impl(T t, std::false_type another_desc_name ){ code }
      

      通过这样做,您可以避免不必要的专业化样板,并通过调整特征类使代码易于扩展。

      方法特化有点古怪,甚至比函数模板特化还要奇怪。根据我的经验,通过使用标签调度,推理发生的事情变得更容易。

      【讨论】:

        【解决方案6】:

        好吧,也许换一种方式思考会更好——你有模板数据结构,所以你应该专门化整个结构而不是一个函数——因为如果你需要为这种类型专门化另一种方法(这里是字符串),你将它专门用于同一类 - 它会稍微破坏代码。我的解决方案变体在上面:

        template <class T> 
        class hashtable{
         public:
            void insert(T item){
                /* Do Stuff */          
                };
        }
        template <string> 
        class hashtable{
         public:
            void insert(string item){
                /* Do different stuff */          
            };
        }
        

        作为版本 - 您可以使用模板哈希函数编写哈希表 - 这将删除任何专业化。但显然,您需要为字符串编写自己的函数。 int 和 hashtable 的示例:

         template <class T>
         LinearHashFunction {
             int a,b;
             static const int prime = /* some big prime number */
             LinearHashFunction(int a, int b):a(a), b(b) {}
             int operator()(T item) {
                 return static_cast<int>(item)*a + b;
             }
         };
        
         template <class T, class THashFunction> 
         class hashtable{
         private:
            THashFunction<T> hash;
         public:
            void insert(T item){
                    /* Do Stuff */
                    // get hash:
                    int elementsHash = hash(item);          
                    };
            template<> void insert(string item){
                    /* Do different stuff */
                    };
            };
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-18
          • 2022-01-09
          • 2020-07-18
          相关资源
          最近更新 更多