Как вы справляетесь со все более длительным временем компиляции при работе с шаблонами?

13

Я использую Visual Studio 2012, и у него есть случаи, когда мы добавляли параметры шаблонов в класс «просто», чтобы ввести «точку шва», чтобы в модульном тесте мы могли заменить эти части на фиктивные объекты.

Как вы обычно вводите точки стыка в C ++: используя интерфейсы и / или смешивание на основе некоторых критериев с неявными интерфейсами, используя также параметры шаблонов? Одной из причин этого также является то, что при компиляции иногда одного файла C ++ (который включает файлы шаблонов, который может также включать другие шаблоны) получается генерируемый объектный файл, который занимает порядка 5-10 секунд на компьютере разработчика ,

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

Каковы ваши способы обработки добавочного (и не только) времени компиляции при работе с шаблонами (помимо лучшего / более быстрого компилятора :-)).

Ghita
источник
1
Интеграция @RobertHarvey осуществляется с использованием параметров шаблона. В производственном коде, где я их создаю, у меня медленные времена компиляции.
Гита
5
Вы используете C ++ 11? см. en.wikipedia.org/wiki/C%2B%2B11#Extern_template
mike30
2
Поскольку Андрей Александреску написал «Современный дизайн C ++», многие программисты на C ++ считают, что они должны использовать шаблоны для всего и вся и позволить компилятору обрабатывать как можно больше. Это обычно приводит к тем эффектам, которые вы описываете. Раньше (и в настоящее время все еще для программистов, использующих другие языки), было абсолютно нормально не использовать шаблоны и обрабатывать такие вещи, как внедрение зависимостей с помощью механики времени выполнения, даже когда для конечного пользователя требуется больше циклов ЦП (что он почти никогда не заметит) ). Честно говоря, я уверен, что Роберт на 100% прав, и это то, что вы думаете об этом.
Док Браун
1
@ Гита: ИМХО, использование шаблонного метапрограммирования часто является просто формой преждевременной оптимизации (а иногда и просто излишним) - поскольку вы не пишете библиотеки типа STL с сопоставимыми требованиями. Вы компенсируете некоторый выигрыш в производительности для большего времени компиляции, меньшего удобства сопровождения и большого количества трудных для понимания сообщений об ошибках. Использование «внешних шаблонов» может помочь вам в краткосрочной перспективе, но если бы я был на вашем месте, я бы также подумал о долгосрочных улучшениях.
Док Браун
4
@DocBrown. И наоборот, можно сказать, что отказ от шаблонов для повышения производительности сборки - это преждевременная оптимизация. Шаблоны являются идеальной абстракцией для многих задач.
mike30

Ответы:

9

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

Например, в aaa.hвас только объявить функции шаблона fи g:

template <int n>
int f();

template <class T>
void g(int a);

Предполагать n , шаблон параметр может быть только 1, 3, 6, и Tпараметр шаблона может быть только int, longи void *.

Затем вы определяете их aaa.cppследующим образом:

template <int n>
int f()
{
    ...
}

template <class T>
void g(int a)
{
    ...
}

template int f<1>();
template int f<3>();
template int f<6>();

template void g<int>(int a);
template void g<long>(int a);
template void g<void *>(int a);

Таким образом, компилятор создает экземпляр шаблона для заданных параметров при компиляции. aaa.cpp . При компиляции клиентского кода предполагается, что определения где-то существуют, и компоновщик позаботится об этом.

#include "aaa.h"

int main()
{
    f<1>();
    f<3>();
    f<6>();

    g<int>(5);
    g<long>(5);
    g<void *>(5);
}

Вы также можете явно создавать экземпляры шаблонных классов. Недостатком является то, что вы не можете использоватьf или gс другими параметрами шаблона.

#include "aaa.h"

int main()
{
    f<5>();
}

результаты в

undefined reference to `int f<5>()'

Я использовал эту технику в проекте, где несколько сложных классов зависели от небольшого (<10) набора целочисленных параметров шаблона, и это значительно сократило время компиляции (поскольку компилятору не приходилось анализировать определения сложных шаблонов при компиляции клиентского кода) , Конечно, вы можете получить меньшие улучшения, в зависимости от реального кода.

Claudio
источник
2

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

Чтобы сохранить дизайн в чистоте, я продолжал поддерживать make-файл, но никогда не использовал его (за исключением проверки, что он все еще работает).

maaartinus
источник
0

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

Ти Стрга
источник