Como você lida com tempos de compilação cada vez mais longos ao trabalhar com modelos?

13

Eu uso o Visual Studio 2012 e ele tem casos em que adicionamos parâmetros de modelos a uma classe "just" para introduzir um "ponto de costura" para que no teste de unidade possamos substituir essas peças por objetos simulados.

Como você geralmente introduz pontos de costura em C ++: usando interfaces e / ou misturando com base em alguns critérios com interfaces implícitas, usando também parâmetros de modelos? Um motivo para perguntar isso é também porque, ao compilar algumas vezes, um único arquivo C ++ (que inclui arquivos de modelos, que também pode incluir outros modelos) resulta na geração de um arquivo de objeto que leva da ordem de 5 a 10 segundos em uma máquina de desenvolvedor .

O compilador VS também não é particularmente rápido na compilação de modelos, tanto quanto eu entendo, e por causa do modelo de inclusão de modelos (você praticamente inclui a definição do modelo em todos os arquivos que o usam indiretamente e, possivelmente, re-instancia o modelo toda vez que você modifica algo que não tem nada a ver com esse modelo), você pode ter problemas com os tempos de compilação (ao fazer a compilação incremental).

Quais são as suas maneiras de lidar com o tempo de compilação incremental (e não apenas) ao trabalhar com modelos (além de um compilador melhor / mais rápido :-)).

Ghita
fonte
1
A injeção de dependência do @RobertHarvey é feita usando parâmetros de modelo. No código de produção, onde eu instanciao estes, tenho tempos de compilação lentos.
Ghita
5
Você está usando C ++ 11? veja en.wikipedia.org/wiki/C%2B%2B11#Extern_template
mike30 28-28
2
Como Andrei Alexandrescu criou o "design moderno de C ++", muitos programadores de C ++ acham que devem usar modelos para tudo e todos e deixar o compilador lidar com o máximo possível. Isso normalmente leva aos efeitos que você está descrevendo. Anteriormente (e atualmente ainda para programadores que usam outras linguagens), era absolutamente aceitável não usar modelos e lidar com coisas como injeção de dependência com mecânica de tempo de execução, mesmo quando isso precisa de alguns ciclos de CPU mais para o usuário final (o que ele quase nunca notará ) Sinceramente, tenho certeza de que Robert está 100% correto e é assim que você pensa.
Doc Brown
1
@Ghita: O IMHO usando a meta-programação de modelos geralmente é apenas uma forma de otimização prematura (e às vezes apenas um exagero) - desde que você não escreva libs como o STL com requisitos comparáveis. Você troca algum ganho de desempenho por tempos de compilação maiores, menos capacidade de manutenção e muitas mensagens de erro difíceis de entender. O uso de "modelos externos" pode ajudá-lo agora a curto prazo, mas se eu estivesse no seu lugar, também pensaria em melhorias a longo prazo.
Doc Brown
4
@DocBrown. Por outro lado, você poderia dizer que evitar modelos para melhorar o desempenho da compilação é uma otimização prematura. Modelos são as abstrações ideais para muitos problemas.
mike30

Respostas:

9

Se os parâmetros de seus modelos puderem assumir apenas um conjunto finito (e pequeno) de valores, você poderá mover sua definição em um arquivo de origem e usar instanciação explícita .

Por exemplo, aaa.hvocê declara apenas as funções do modelo fe g:

template <int n>
int f();

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

Suponha que o nparâmetro do modelo possa ser apenas 1, 3, 6 e o Tparâmetro do modelo possa ser apenas int, longe void *.

Então você os define da aaa.cppseguinte maneira:

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);

Dessa maneira, o compilador instancia o modelo para os parâmetros fornecidos ao compilar aaa.cpp. Ao compilar o código do cliente, ele assume que as definições existem em algum lugar, e o vinculador cuidará disso.

#include "aaa.h"

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

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

Você também pode instanciar explicitamente as classes de modelo. A desvantagem é que você não pode usar fou gcom outros parâmetros de modelo.

#include "aaa.h"

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

resulta em

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

Usei essa técnica em um projeto em que poucas classes complexas dependiam de um pequeno (<10) conjunto de parâmetros de modelo inteiro e reduziu significativamente o tempo de compilação (já que o compilador não precisou analisar as definições de modelo complexo ao compilar o código do cliente) . Claro que você pode obter melhorias menores, dependendo do código real.

Claudio
fonte
2

Certa vez, usei uma solução estranha para um problema semelhante: incluir o STL leva a tempos de compilação como vários segundos por arquivo de origem - não importa quão pequeno seja. Então, incluí todos os meus arquivos de origem em um arquivo mestre e o tempo de compilação por arquivo quase não mudou ... o que significou uma velocidade de fator 20 ou mais, pois eu tinha apenas um único arquivo para compilar.

Para manter o design limpo, continuei mantendo um makefile, mas nunca o usei de verdade (exceto para verificar se ainda funciona).

maaartinus
fonte
0

Costumávamos disparar uma grande tarefa para criar nossos cabeçalhos pré-compilados e modelos pré-compilados da noite para o dia, e apenas compilá-los no dia seguinte.

Ti Strga
fonte