Question

I would like to add to a template class a constructor that builds a specialized object with some initializations. This is the class I'm working on:

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

Now I would like to

typedef t_simple_db<string,double> t_simple_db_sd;

and to write a special constructor for it so that in the main I can simply call something like this:

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

having a correct instantiated and initialized object. I tried to place this in the header after the class declaration:

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

but I get a bunch of multiple definition errors when I try to compile.

Was it helpful?

Solution

If this is your class template:

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

Then any (implicit) specialization only has a default constructor. You could

  1. Add a non-default ctor to the (primary) class template

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

    In order to define the ctor outside the class definition, put in the header file:

    template <typename Tkey, typename Tdata>
    t_simple_db::t_simple_db() { /* ... */ }
    
  2. Partially or explicitly specialize the class template

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

    In order to define the ctor outside the class definition: Explicitly (= fully) specialized class templates are "ordinary" classes, not templates (you cannot create types from them, they are types with strange names). Therefore, the usual rules for functions + ODR apply: preferably put them into the source file (cpp), alternatively as inline or with internal linkage in the header file

    // 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(..) { /*...*/ }
    

In your pastebin, there's a ctor

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

I wouldn't recommend putting this ctor in the primary template: Not all specializations of t_simple_db might use strings as Tkeys. You can use inheritance to provide an additional ctor only for certain specializations, e.g.

// 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)
{
    /*...*/
}

The reason why this function must be in the source file is that it is not a template. I.e., it's not a blueprint that the compiler uses to make functions, but it's a complete function itself. Therefore, it needs to follow the One Definition Rule. As opposed to templates and members of class templates, the linker does not merge the definitions. You can also provide the definition inside the class definition, implicitly making the function inline. It's possible as well to provide that definition in the header file outside the class definition, if you explicitly mark the function as inline. If the function is inline, it may appear in multiple translation units.

It is also possible to declare the ctor for all specializations but only define it for t_simple_db<std::string, double>. I don't recommend this approach because misusing the ctor for other specializations will only cause a linker error. Nevertheless, here's how you can do that:

// 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)
{
    /*...*/
}

This function isn't a template either, so the same rules apply as for the member function of an explicit specialization / as for normal functions.

OTHER TIPS

There is a way using variadic templates to do something like this:

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)... );
          }
     }
 };
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top