Сможет ли создание экземпляров шаблонов в предварительно скомпилированных заголовках сократить время компиляции?

Пример:
Скажем, я включаю в свой предварительно скомпилированный заголовочный файл:

#include <vector>

Поскольку несколько экземпляров вектора, таких как std :: vector, std :: vector и т. Д., Часто используются в моем проекте, это уменьшит время компиляции, если я создам их экземпляры также в предварительно скомпилированном заголовке следующим образом:

#include <vector>
template class std::vector<float>;
template class std::vector<int>;

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

namespace pch_detail {
inline auto func() {
auto&& v = std::vector<float>{};
v.size();
v.begin();
v.front();
}
}

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

Обновить

Протестировано на реальной базе кода с Visual Studio 2017 и некоторыми экземплярами часто используемых шаблонных классов.

  1. С экземпляром общего шаблонного класса: 71731 мс
  2. Без создания экземпляра: 68544 мс

Следовательно, по крайней мере, в моем случае это заняло немного времени.

3

Решение

Забавная вещь, но хотя бы для clang (4.0.1) ваш вариант увеличивает время компиляции:

1. no pch

real    0m0,361s
user    0m0,340s
sys     0m0,021s

2. pch, no explicit instantiate

real    0m0,297s
user    0m0,280s
sys     0m0,017s

3. pch, explicit instantiate

real    0m0,507s
user    0m0,474s
sys     0m0,033s

Я использую такой код:

#include <iostream>
#include "test.h"
int main() {
std::vector<float> a = {1., 2., 3.};
for (auto &&e : a) {
std::cout << e << "\n";
}
std::vector<int> b = {1, 2, 3};
for (auto &&e : b) {
std::cout << e << "\n";
}
}

кейс 2 test.h

#pragma once

#include <vector>

случай 3

#pragma once

#include <vector>
template class std::vector<float>;
template class std::vector<int>;

и такой скрипт компиляции:

echo "no pch"time clang++ -std=c++11 main.cpp

echo "pch, no explicit instantiate"clang++ -std=c++11 -x c++-header test.h -o test.pch
time clang++ -std=c++11 -include-pch  test.pch main.cpp

echo "pch, explicit instantiate"clang++ -std=c++11 -x c++-header test2.h -o test2.pch
time clang++ -std=c++11 -include-pch  test2.pch main2.cpp
4

Другие решения

Это может иметь значение, да.

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

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

3

Я тоже думал об этом, и у меня тоже есть этот вопрос. (Но я нуб …)

Еще одна ссылка: https://msdn.microsoft.com/en-us/library/by56e477.aspx

Может быть явным extern нужно?

Однако, когда пришло время связать, файлы cpp были скомпилированы в .objх, но .pch это не .obj
Тогда, где будет происходить реализация функций шаблона? Будет ли компоновщик читать вещи из .pch?

Или нам нужен еще один отдельный .cpp выделенный для их создания, при этом все клиентские ссылки объявляются как extern?

И .. Генерация кода Link-Time?

Были некоторые попытки

Это работает немного. Тестирование с VS2012. Включите профилирование компилятора и просмотрите выходные данные компилятора.

// stdafx.h
#pragma once

#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <stdlib.h>

#include <vector>
#include <set>
#include <deque>

// stdafx.cpp
#include "stdafx.h"
using namespace std;

template class set<int>;
template set<int>::set();
template set<int>::_Pairib set<int>::insert(const int&);

template class deque<int>;
template deque<int>::deque();
template void deque<int>::push_back(const int&);

template class vector<int>;
template vector<int>::vector();
template void vector<int>::push_back(const int&);

// playcpp.cpp, the entry point

#include "stdafx.h"
using namespace std;
// toggle this block of code
// change a space in the "printf", then build (incrementally)
/*
extern template class set<int>;
extern template set<int>::set();
extern template set<int>::_Pairib set<int>::insert(const int&);

extern template class deque<int>;
extern template deque<int>::deque();
extern template void deque<int>::push_back(const int&);

extern template class vector<int>;
extern template vector<int>::vector();
extern template void vector<int>::push_back(const int&);
*/

int _tmain(int argc, _TCHAR* argv[])
{
set<int> s;
deque<int> q;
vector<int> v;
for(int i=0;i<10000;i++){
int choice=rand()%3;
int value=rand()%100;
switch(choice){
case 0: s.insert(value); break;
case 1: q.push_back(value); break;
case 2: v.push_back(value); break;
}
}
for(const auto &i:s)
printf("%d",i);
for(const auto &i:q)
printf("%d ",i);
for(const auto &i:v)
printf("%d ",i);
return 0;
}

результаты (многие другие опущены)

с внешними декларациями:

1>               1630 毫秒  Build                                      1 次调用
...
1>      757 毫秒  ClCompile                                  1 次调用
1>      787 毫秒  Link                                       1 次调用

без внешних деклараций:

1>               1801 毫秒  Build                                      1 次调用
...
1>      774 毫秒  Link                                       1 次调用
1>      955 毫秒  ClCompile                                  1 次调用

(Китайская версия. Легенды: ms : мс / миллисекунды , x 次 调用 : х звонит / звонит х раз)

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

Выше только один образец для каждого случая. Тем не менее, это довольно нестабильно. Оба случая могут иногда работать на ~ 200 мс больше.

Но пытаясь много раз, всегда есть разница около 200 мс в среднем. Я могу просто сказать, что средние значения составляют около 1650 мс и 1850 мс, со всей разницей во времени ClCompile.

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

Ну, но тогда …. Есть ли лучшие способы сделать это?

1
По вопросам рекламы [email protected]