2014-01-21 2 views
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 
}; 

Теперь я хотел бы

typedef t_simple_db<string,double> t_simple_db_sd; 

и написать специальный конструктор для него, так что в основном я могу просто назвать что-то вроде этого:

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

, но я получаю кучу ошибок нескольких определений при попытке компиляции.

+6

Можете ли вы показать нам, что вы пробовали до сих пор? – dyp

+0

Если у вас есть C++ 11, вы можете использовать для него вариационный шаблон, поэтому класс ... Args как параметр шаблона. – CashCow

+0

@dyp НЕ принимайте случайный пример как вопрос. Это можно сделать несколькими путями. Дело в том, как написать конструктор, который возвращает специализированный объект. – DarioP

ответ

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. Добавить нестандартную CT к (первичному) шаблону

    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 вне определения класса: Явный (= полностью) специализированные шаблоны классов являются «обычные» классы, не шаблонов (Вы не можете создавать типы из них, они являются типов с странные имена). Поэтому обычные правила для функций + УСО применяются: предпочтительно поместить их в исходный файл (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(..) { /*...*/ } 
    

В вашем Pastebin, есть т е р

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

Я не рекомендовал бы поставить этот CTOR в основном шаблоне: не все специализации t_simple_db могут использовать string с, как Tkey с. Вы можете использовать наследование для предоставления дополнительного 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) 
{ 
    /*...*/ 
} 

Причина, почему эта функция должна быть в исходном файле, что это не шаблон. I.e., это не проект, который компилятор использует для , делает функции, но это полная функция. Следовательно, он должен следовать правилу Единого определения. В отличие от шаблонов и членов шаблонов классов, компоновщик не объединяет определения. Вы также можете указать определение внутри определения класса, неявно делая функцию 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) 
{ 
    /*...*/ 
} 

Эта функция не шаблон либо, так что одни и те же правила, что и для функции члена явной специализации/как и для обычных функций.

+0

Мне бы очень хотелось подняться и принять, но я не могу пойти ни с одним из этих методов. Я продолжаю получать несколько определений или ошибок, не соответствующих объявлениям шаблонов. Я не понимаю, как правильно идти. pfff Я трачу столько времени на это :( – DarioP

+0

@DarioP Не могли бы вы предоставить [самодостаточный пример] (http://sscce.org), который воспроизводит проблему? Самое главное, пожалуйста, включите * где * вы положили части вашего кода (заголовок/исходный файл). – dyp

+0

@DarioP Похоже, вы комбинировали *, не специализирующийся на шаблоне класса с внеуровневым определением ctor для явно специализированного шаблона класса * в одном случае и * явно специализируясь на шаблоне класса, но предоставляя внеочередное определение ctor в файле заголовка * в другом случае. – dyp

0

Существует способ использования VARIADIC шаблонов, чтобы сделать что-то вроде этого:

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)...); 
      } 
    } 
}; 
+0

Это новое для меня, и я не могу обещать, что синтаксис работает точно, но это возможно с использованием вариативных шаблонов. – CashCow

+0

Мне не нужно ничего подобного. У меня нет аргументов ... может быть, вопрос недостаточно ясен. – DarioP

+0

Вы забыли 'std :: forward' и операции с многоточием:' Args && ... args', 'T (std: forward (args) ...)'. Но вы не можете сделать это таким образом: цикл 'for' не подходит для итерации через параметры вариационного шаблона. – Constructor

Смежные вопросы