Як ви обробляєте все більш тривалий час компіляції під час роботи з шаблонами?


13

Я використовую Visual Studio 2012, і у нього є випадки, коли ми додавали параметри шаблонів до класу "просто", щоб ввести "точку шва", щоб в блок-тесті ми могли замінити ці частини на макетні об'єкти.

Як ви зазвичай вводите точки шва в C ++: використовуючи інтерфейси та / або змішуючи на основі деяких критеріїв із неявними інтерфейсами, використовуючи також параметри шаблонів? Одна з причин запитувати це також полягає в тому, що при компіляції іноді одного файлу C ++ (який включає файли шаблонів, які також можуть включати інші шаблони) в результаті створюється об’єктний файл, який займає близько 5-10 секунд на машині розробника .

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

Які ваші способи поводження з додатковим (і не тільки) часом збирання під час роботи з шаблонами (крім кращого / швидшого компілятора :-)).


1
Введення залежності @RobertHarvey проводиться за допомогою параметрів шаблону. У виробничому коді, де я створюю ці дані, у мене є повільні компіляції.
Ghita

5
Ви використовуєте C ++ 11? дивіться en.wikipedia.org/wiki/C%2B%2B11#Extern_template
mike30

2
Оскільки Андрій Олександреску написав "Сучасний дизайн C ++", багато програмістів на C ++ думають, що вони повинні використовувати шаблони для всіх і всього, і дозволити компілятору якомога більше обробляти. Це, як правило, призводить до тих ефектів, які ви описуєте. Раніше (і в даний час для програмістів, які використовують інші мови), абсолютно нормально було не використовувати шаблони та обробляти такі речі, як введення залежності залежно від механіки часу роботи, навіть коли для кінцевого користувача це потребує певних циклів процесора (що він майже ніколи не помітить) ). Чесно кажучи, я впевнений, що Роберт на 100% правильний, і саме так ви думаєте про це.
Doc Brown

1
@Ghita: ІМХО з використанням мета-програмування шаблонів часто є лише формою передчасної оптимізації (а іноді і просто надмірної кількості) - наскільки ви не пишете лайфів, як STL із порівнянними вимогами. Ви компенсуєте певну прибутковість для збільшення часу компіляції, меншої ремонтопридатності та безлічі важких для розуміння повідомлень про помилки. Використання "зовнішніх шаблонів" може допомогти вам у короткостроковому періоді, але якби я був у вашому взутті, я б також подумав про довгострокові вдосконалення.
Doc Brown

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) набору цілих параметрів шаблону, і це значно скоротило час компіляції (оскільки компілятору не довелося розбирати складні визначення шаблону під час компіляції клієнтського коду) . Звичайно, ви можете отримати менші вдосконалення, залежно від фактичного коду.


2

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

Щоб зберегти дизайн чистим, я продовжував підтримувати файл makefile, але фактично його не використовував (за винятком перевірки, що він все ще працює).


0

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.