模板类的专用构造函数

时间:2014-01-21 17:02:53

标签: c++ templates constructor template-specialization

我想在模板类中添加一个构造函数,该构造函数构建一个带有一些初始化的专用对象。这是我正在上课的课程:

template <typename Tkey, typename Tdata> class t_simple_db{
 private:
  typedef typename std::list<std::pair<Tkey,vector<Tdata>>> t_internal;
  t_internal _db;

 public:
  typedef typename t_internal::const_iterator const_iterator;
  typedef typename t_internal::iterator iterator;

  t_simple_db(){;}
  ~t_simple_db(){;}

  //many methods
};

现在我想

typedef t_simple_db<string,double> t_simple_db_sd;

并为它编写一个特殊的构造函数,以便在main中我可以简单地调用这样的东西:

t_simple_db_sd db("this is a string", 100u);

拥有正确的实例化和初始化对象。我试图在类声明之后将它放在标题中:

typedef t_simple_db<string, double> t_simple_db_sd;
template<> t_simple_db<string, double>::t_simple_db(...) {
  ...
}

但是当我尝试编译时,我得到了一堆多重定义错误。

2 个答案:

答案 0 :(得分:1)

如果这是您的班级模板:

template <typename Tkey, typename Tdata> class t_simple_db{
 private:
  typedef typename std::list<std::pair<Tkey,vector<Tdata>>> t_internal;
  t_internal _db;

 public:
  typedef typename t_internal::const_iterator const_iterator;
  typedef typename t_internal::iterator iterator;

  t_simple_db(){;}
  ~t_simple_db(){;}

  //many methods
};

然后任何(隐式)特化只有一个默认构造函数。你可以

  1. 将非默认ctor添加到(主)类模板

    template <typename Tkey, typename Tdata> class t_simple_db{
      /* ... */
    
      t_simple_db(){;}
      t_simple_db(Tkey, std::size_t n) { /*...*/ }
      ~t_simple_db(){;}
    
      //many methods
    };
    

    为了在类定义之外定义ctor,请输入头文件

    template <typename Tkey, typename Tdata>
    t_simple_db::t_simple_db() { /* ... */ }
    
  2. 部分或明确地专门化类模板

    template <> class t_simple_db<std::string, double>{
      /* ... */
      t_simple_db(std::string, std::size_t n) { /*...*/ }
      ~t_simple_db(){}
    
      //many methods
    };
    

    为了在类定义之外定义ctor:显式(=完全)专用类模板是“普通”类,而不是模板(不能从中创建类型他们,是具有奇怪名称的类型)。因此,函数+ ODR的通常规则适用:最好将它们放入源文件(cpp),或者作为inline或者在头文件中使用内部链接

    // no `template`
    t_simple_db<std::string, double>::t_simple_db(..) { /*...*/ }
    
    // or
    typedef t_simple_db<string, double> t_simple_db_sd;
    t_simple_db_sd::t_simple_db(..) { /*...*/ }
    

  3. 在你的pastebin中,有一个ctor

    t_simple_db(const string& keys, const size_t& res );
    

    我不建议将此ctor放在主模板中:并非t_simple_db的所有专精都可以将string用作Tkey s。您可以使用继承为某些特殊化提供额外的ctor,例如

    // header file
    
    template <typename Tkey, typename Tdata> class t_simple_db_base{
     public:
      t_simple_db_base(){;}
      ~t_simple_db_base(){;} // possibly virtual
    
      //many methods
    };
    
    template <typename Tkey, typename Tdata>
    class t_simple_db : public t_simple_db_base<Tkey, Tdata>{
     public:
      t_simple_db(){;}
      ~t_simple_db(){;}
    };
    
    // explicit specialization of `t_simple_db`
    template <>
    class t_simple_db<std::string, double>
        : public t_simple_db_base<std::string, double>{
     public:
      t_simple_db(){;}
      t_simple_db(const string& keys, const size_t& res);
      ~t_simple_db(){;}
    };
    
    typedef t_simple_db<std::string, double> t_simple_db_sd;
    
    
    // source file
    
    //template <>  <-- not a member function of a class template,
    //                 but of an "ordinary class"
    t_simple_db_sd::t_simple_db(const string& keys, const size_t& res)
    {
        /*...*/
    }
    

    此函数必须在源文件中的原因是它不是模板。即,它不是编译器用于制作函数的蓝图,但它本身就是一个完整的函数。因此,它需要遵循一个定义规则。与模板和类模板成员相反,链接器不会合并定义。您还可以在类定义中提供定义,隐式地创建函数inline。如果明确将函数标记为inline,也可以在类定义之外的头文件中提供该定义。如果函数为inline,则它可能出现在多个翻译单元中。

    也可以为所有特化声明ctor,但只为t_simple_db<std::string, double>定义它。我不推荐这种方法,因为滥用ctor进行其他特化只会导致链接器错误。不过,这是你如何做到的:

    // header file
    
    template <typename Tkey, typename Tdata> class t_simple_db{
     public:
      t_simple_db(){;}
      t_simple_db(const string& keys, const size_t& res );
      ~t_simple_db(){;}
    
      //many methods
    };
    
    typedef t_simple_db<std::string, double> t_simple_db_sd;
    
    
    // source file
    template <>   // <-- this is a member function of a class template,
                  //     therefore we need the `template <>`
                  //     in this example, t_simple_db_sd is *not* an explicit
                  //     specialization
    t_simple_db_sd::t_simple_db(const string& keys, const size_t& res)
    {
        /*...*/
    }
    

    此函数也不是模板,因此适用与显式特化的成员函数相同的规则/正常函数。

答案 1 :(得分:0)

使用可变参数模板可以这样做:

template< typename T, typename Alloc >
class MyVector
{
 private:
      T* mem;
 public:

     template< Class... Args >
     MyVector( size_t i, Args &&... args )
     {
          mem = Alloc::alloc( i ); // "pseudo" code to allocate the memory
          for( size_t idx = 0; idx < i; ++idx )
          {
             new ( mem + idx )  T( std::forward<Args>(args)... );
          }
     }
 };