2013-11-14 4 views
0

Я понимаю, что определения шаблонов должны быть помещены в файл заголовка. Означает ли это, что все определения классов, которые шаблон использует (прямо или косвенно), необходимо помещать в файлы заголовков?о шаблоне кода orginisation: где поставить код, который использует шаблон

У меня есть шаблон, который имеет много классов, от которых он зависит, и, следовательно, должен помещать их все в файл заголовка, иначе я получу «ошибку LNK2019: неразрешенный внешний символ». Есть ли лучшее решение в плане организации кода?

Пример:

double inline MainFunction(double price, const Params& params) 
    { 
     Price<ModeEnum::NORMAL> pricer(price); 
     MethodOne<ModeEnum::NORMAL> methodOne; 
     return pricer.func(methodOne, params) ;  
    } 


template<ModelEnum::Enum Mode> 
struct Price 
{ 
    double price; 
    typedef double return_type; 
    Price(double price_) : price(price_){} 

    template<typename T> double func(const T& method, const Params& params) const 
    { 
     const typename T::PriceFactor factor(params); 
     return factor ..... ; 
    } 
}; 

Т :: PriceFactor фактически класс В, что является определение типа определено в tempalte метадона. Из-за этого я должен поместить конструктор класса B и все (много) функции и класс, которые он использует в заголовочном файле.

+0

Вы по-прежнему можете использовать '# include' для разделения различных классов между файлами. Можете ли вы дать небольшой пример, только с именами фиктивных классов? – pippin1289

+0

[Вперед объявить] (http://stackoverflow.com/questions/4757565/c-forward-declaration) все, что вы можете. –

+0

хорошо. это tempalte. Поэтому я думаю, что тело также очень важно – KKKoo0

ответ

2

Простой ответ: весь код должен быть видимым компилятору при создании экземпляра шаблона. Если код не отображается, компилятор не будет создавать экземпляр, и вам нужно будет предоставить явное инстанцирование. Если явная конкретизация жизнеспособна, зависит от характера вашего шаблона:

  1. шаблонов, которые применимы ко многим типам, например, что-то вроде std::vector<T>, вероятно, хотят быть полностью реализованы в заголовке. Вы можете отделить декларацию и определение шаблонов функций, но нет смысла указывать детали в разные файлы.
  2. шаблоны, которые применимы к некоторым типам, например, std::basic_ostream<cT> который конкретизируется с char, wchar_t и, возможно, в какой-то момент с char16_t и char32_t вероятно, хотят быть объявлены в заголовке и определен в другом заголовке, который не автоматически включается , Вместо этого заголовок с определениями включается только в специальные файлы экземпляров, где шаблоны классов явно создаются.
  3. Некоторые шаблоны предоставляют классы с различными свойствами одного и того же интерфейса. Это имело место в случае с std::complex<T>, который может быть создан с помощью float, double и long double. Для таких шаблонов заголовок будет включать только объявления, и определения будут переведены в подходящую единицу перевода.
  4. Одна из тем, которая ортогональна вышеприведенному обсуждению, заключается в факторизации общих частей, в идеале в нешаблонах, в шаблоны с меньшим количеством экземпляров: вполне возможно, что можно использовать очень общий интерфейс, но реализовать его с точки зрения более ограничительный интерфейс за счет того, чтобы каким-то образом устранить пробел как часть реализации шаблона. В этом случае «интересная» реализация может перейти в исходный файл, а не в заголовок, а шаблоны в интерфейсе просто адаптируют переданные типы к фактической реализации.

При упоминании выше этого кода будет место в исходный файл этого, относится, очевидно, только для нетривиального кода: простые функции переадресации, вероятно, должны остаться inline функции по соображениям производительности. Однако они, как правило, не являются интересными шаблонами функций, вызывающими множество зависимостей.

Для получения более полной информации о том, как организовать код шаблона, см. Это blog entry.

0

Если его просто, я просто положить все это в одном заголовке:

//simple_template.h 
#ifndef SIMPLE_TEMPLATE_H 
#define SIMPLE_TEMPLATE_H 
template <typename T> 
class SomethingSimple 
{ 
public: 
    T foo() { return T();} 
}; 
#endif 

Если это сложнее, я создать «встроенный заголовок» (и использовать соглашение об именах из руководства по стилю Google), чтобы получить:

//complicated_template.h 
#ifndef COMPLICATED_TEMPLATE_H 
#define COMPLICATED_TEMPLATE_H 
template <typename T> 
class SomethingComplicated 
{ 
public: 
    T foo(); 
}; 
#include "compilcated_template-inl.h" 
#endif 

//compilcated_template-inl.h 
#ifndef COMPLICATED_TEMPLATE_INL_H 
#define COMPLICATED_TEMPLATE_INL_H 
#include "complicated_template.h" 
template <typename T> 
T SomethingComplicated<T>::foo() {/*lots of code here*/; return T();} 
#endif 

Таким образом, complicated_template.h довольно читаемый, но любой, кто использует шаблон просто может включать этот заголовок. Например,

//uses_template.h 
#ifndef USES_TEMPLATE_H 
#define USES_TEMPLATE_H 
#include "complicated_template.h" 
class something_using_complicated 
{ 
private: 
    SomethingComplicated<int> something_; 
}; 

Примечания: если классы, которые используют шаблон также шаблоны классов, то вы застряли с только заголовком библиотеки. Вот почему BOOST - это главным образом заголовки.

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