лучшие практики: включить файл .cpp в main вместо файла .h при использовании шаблонов? [Дубликат]

datePickerDialog = new DatePickerDialog(ProfileActivity.this, this, year, month, day);
datePickerDialog.getDatePicker().setMinDate(System.currentTimeMillis());
datePickerDialog.setTitle("");
datePickerDialog.show();

следует добавить datePickerDialog.getDatePicker (). setMinDate (System.currentTimeMillis ()); а затем добавьте datePickerDialog.setTitle ("");

этот тип последовательности для удаления верхнего заголовка белого фона

392
задан Leon Timmermans 29 September 2008 в 16:56
поделиться

10 ответов

В последнем стандарте есть ключевое слово (export), которое поможет устранить эту проблему, но оно не реализовано ни в компилере, о котором я знаю, кроме Comeau.

Об этом можно узнать в FAQ-lite .

4
ответ дан Ben Collins 19 August 2018 в 10:49
поделиться
  • 1
    AFAIK, экспорт мертв, потому что они сталкиваются с новыми и новыми проблемами, каждый раз, когда они разрешают последнее, что делает общее решение все более сложным. И & quot; экспорт & quot; ключевое слово не позволит вам экспортировать & quot; от CPP в любом случае (по-прежнему от Х. Саттера). Поэтому я говорю: не задерживайте дыхание ... – paercebal 22 September 2008 в 17:25
  • 2
    Для реализации экспорта компилятор по-прежнему требует полного определения шаблона. Все, что вы получаете, это иметь его в виде скомпилированной формы. Но на самом деле нет никакого смысла. – Zan Lynx 12 March 2012 в 18:56
  • 3
    ... и это ушел из стандарта, из-за чрезмерного усложнения для минимального усиления. – DevSolar 26 August 2015 в 13:04

Нет ничего плохого в примере, который вы указали. Но я должен сказать, что считаю, что неэффективно хранить определения функций в файле cpp. Я понимаю только необходимость отделить декларацию и определение функции.

При использовании вместе с явным созданием класса, библиотека проверки возможностей Boost (BCCL) может помочь вам сгенерировать код функции шаблона в файлах cpp.

0
ответ дан Benoît 19 August 2018 в 10:49
поделиться

Ваш пример правильный, но не очень портативный. Существует также несколько более чистый синтаксис, который можно использовать (как указано в @ namespace-sid).

Предположим, что шаблонный класс является частью некоторой библиотеки, которая должна быть разделена. Должны ли компилироваться другие версии шаблонного класса? Предполагается ли разработчик библиотеки предвидеть все возможные шаблонные применения класса?

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

foo.h file

// Standard header file guards omitted

template <typename T>
class foo
{
public:
    void bar(const T& t);
};

foo.cpp file

// Always include your headers
#include "foo.h"

template <typename T>
void foo::bar(const T& t)
{
    // Do something with t
}

foo-impl.cpp file

// Yes, we include the .cpp file
#include "foo.cpp"
template class foo<int>;

caveat заключается в том, что вам нужно сообщить компилятору компилировать foo-impl.cpp вместо foo.cpp, поскольку компиляция последнего ничего не делает.

Конечно, вы можете иметь несколько реализаций в третьем файле или иметь несколько файлов реализации для каждого типа, который вы хотели бы использовать.

Это дает гораздо большую гибкость при совместном использовании шаблона для других целей.

Эта настройка также сокращает время компиляции для повторно используемых классов, повторно не перекомпилировать один и тот же заголовочный файл в каждой единицы перевода.

4
ответ дан Cameron Tacklind 19 August 2018 в 10:49
поделиться
  • 1
    что вы покупаете? Вам необходимо изменить foo-impl.cpp, чтобы добавить новую специализацию. – MK. 22 March 2017 в 15:16
  • 2
    Разделение деталей реализации (также определений в foo.cpp), из которых версии фактически скомпилированы (в foo-impl.cpp) и деклараций (в foo.h). Мне не нравится, что большинство шаблонов C ++ полностью определены в файлах заголовков. Это противоречит стандарту C / C ++ пар c[pp]/h для каждого класса / пространства имен / любой группы, которую вы используете. Люди, похоже, все еще используют монолитные файлы заголовков просто потому, что эта альтернатива широко не используется или не известна. – Cameron Tacklind 29 March 2017 в 20:06

Время обновления! Создайте встроенный (.inl или, возможно, любой другой) файл и просто скопируйте все свои определения в нем. Не забудьте добавить шаблон над каждой функцией (template <typename T, ...>). Теперь вместо включения файла заголовка в встроенный файл вы делаете обратное. Включите встроенный файл после объявления вашего класса (#include "file.inl").

Я действительно не знаю, почему никто не упомянул об этом. Я не вижу немедленных недостатков.

-1
ответ дан Didii 19 August 2018 в 10:49
поделиться
  • 1
    Непосредственные недостатки - это принципиально то же самое, что просто определить функции шаблона непосредственно в заголовке. Когда вы #include "file.inl", препроцессор собирается вставить содержимое file.inl прямо в заголовок. Независимо от причины, по которой вы хотели избежать реализации в заголовке, это решение не решает эту проблему. – Cody Gray♦ 25 June 2013 в 04:38
  • 2
    - и означает, что вы технически необоснованно обременяете себя заданием написать весь подробный, умопомрачительный шаблон, необходимый для определения out-of-line template. Я понимаю, почему люди хотят это сделать - для достижения максимальной четкости с не-шаблонами объявлений / определений, чтобы поддерживать декларацию интерфейса, выглядящую аккуратно, и т. Д. - но это не всегда стоит хлопот. Это случай оценки компромиссов с обеих сторон и выбор наименее плохой . ... до namespace class становится вещью: O [, пожалуйста, будь то ] – underscore_d 2 August 2016 в 20:52
  • 3
    @underscore_d, который определенно должен стать чем-то ... – Andrew 14 September 2016 в 09:43
  • 4
    @Andrew Кажется, что он застрял в трубах Комитета, хотя я думаю, что видел, что кто-то сказал, что это не было преднамеренным. Хотелось бы, чтобы это превратилось в C ++ 17. Может быть, следующее десятилетие. – underscore_d 14 September 2016 в 10:05
  • 5
    @CodyGray: Технически, это действительно то же самое для компилятора, и поэтому не сокращает время компиляции. Тем не менее, я думаю, что это стоит упомянуть и практиковать в ряде проектов, которые я видел. Переход по этой дороге помогает отделить интерфейс от определения, что является хорошей практикой. В этом случае это не помогает с совместимостью ABI и т.п., но облегчает чтение и понимание интерфейса. – kiloalphaindia 7 May 2018 в 09:29

Этот код хорошо сформирован. Вам нужно только обратить внимание на то, что определение шаблона видимо в момент создания экземпляра. Чтобы процитировать стандарт, § 14.7.2.4:

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

16
ответ дан Konrad Rudolph 19 August 2018 в 10:49
поделиться
  • 1
    Что означает не экспортируемый ? – Dan Nissenbaum 12 June 2014 в 20:29
  • 2
    @Dan Видимый только внутри его блока компиляции, а не вне его. Если вы связываете несколько единиц компиляции вместе, экспортируемые символы могут использоваться через них (и должны иметь один или, по крайней мере, в случае шаблонов, согласованные определения, иначе вы запускаете UB). – Konrad Rudolph 12 June 2014 в 20:32
  • 3
    Благодарю. Я думал, что все функции (по умолчанию) видны вне блока компиляции. Если у меня есть две единицы компиляции a.cpp (определяющие функцию a() {}) и b.cpp (определяющие функцию b() { a() }), то это будет успешно связываться. Если я прав, то приведенная цитата, похоже, не будет применяться к типичному случаю ... я что-то не так? – Dan Nissenbaum 12 June 2014 в 20:46
  • 4
    @Dan Тривиальный контрпример: функции inline – Konrad Rudolph 12 June 2014 в 21:02
  • 5
    Шаблоны @Dan Function неявно inline. Причина в том, что без стандартизованного C ++ ABI трудно / невозможно определить эффект, который в противном случае он имел бы. – Konrad Rudolph 12 June 2014 в 22:41

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

Изменить: исправлено на основе комментария.

3
ответ дан Lou Franco 19 August 2018 в 10:49
поделиться
  • 1
    Будучи разборчивым по терминологии, это «явный экземпляр». – Richard Corden 22 September 2008 в 17:19

Это должно хорошо работать везде, где поддерживаются шаблоны. Явное создание экземпляра шаблона является частью стандарта C ++.

10
ответ дан moonshadow 19 August 2018 в 10:49
поделиться

Для других на этой странице, интересующихся, что такое правильный синтаксис (как и я) для явной специализированности шаблонов (или, по крайней мере, в VS2008), его следующее ...

В вашем .h-файле. ..

template<typename T>
class foo
{
public:
    void bar(const T &t);
};

И в вашем .cpp файле

template <class T>
void foo<T>::bar(const T &t)
{ }

// Explicit template instantiation
template class foo<int>;
87
ответ дан Qix 19 August 2018 в 10:49
поделиться
  • 1
    Чтобы дополнить ответ, ссылка ссылается на вопрос положительно, т. Е. Можно сделать то, что предложил Роб, и иметь код для переносимости. – ivotron 1 May 2011 в 22:46
  • 2
    Вы имеете в виду & quot; для явного шаблона шаблона CLASS ?. В этом случае это будет охватывать каждую функцию, которую имеет шаблонный класс? – Arthur 21 February 2013 в 15:57
  • 3
    Можете ли вы просто опубликовать соответствующие части в самом ответе? Почему такая ссылка даже разрешена на SO. Я не знаю, что искать в этой ссылке, поскольку с тех пор она сильно изменилась. – Ident 16 August 2015 в 21:57

Это определенно не неприятный хак, но имейте в виду, что вам нужно будет сделать это (явная спецификация шаблона) для каждого класса / типа, который вы хотите использовать с данным шаблоном. В случае МНОГИХ типов, запрашивающих создание шаблона, может быть много строк в вашем .cpp-файле. Чтобы исправить эту проблему, вы можете иметь TemplateClassInst.cpp в каждом проекте, который вы используете, чтобы у вас было больше контроля над тем, какие типы будут созданы. Очевидно, что это решение не будет идеальным (ака серебряная пуля), так как вы можете сломать ODR:).

5
ответ дан Red XIII 19 August 2018 в 10:49
поделиться
  • 1
    Вы уверены, что это нарушит ODR? Если строки экземпляра в TemplateClassInst.cpp относятся к идентичному исходному файлу (содержащему определения функции шаблона), не гарантируется ли это, что он не нарушает ODR, поскольку все определения идентичны (даже если они повторяются)? – Dan Nissenbaum 12 June 2014 в 20:36
  • 2
    Пожалуйста, что такое ODR? – nonremovable 22 June 2018 в 11:45
0
ответ дан Cássio Renan 30 October 2018 в 23:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: