Bagaimana Anda menangani waktu kompilasi yang semakin lama saat bekerja dengan templat?

13

Saya menggunakan Visual Studio 2012 dan dia memiliki kasus di mana kami menambahkan parameter template ke kelas "hanya" untuk memperkenalkan "titik jahitan" sehingga dalam unit-test kita dapat mengganti bagian-bagian itu dengan benda tiruan.

Bagaimana Anda biasanya memperkenalkan titik jahitan di C ++: menggunakan antarmuka dan / atau pencampuran berdasarkan beberapa kriteria dengan antarmuka implisit dengan menggunakan parameter templat juga? Salah satu alasan untuk menanyakan hal ini juga karena ketika mengkompilasi kadang-kadang satu file C ++ (yang termasuk file templat, yang juga bisa menyertakan templat lain) menghasilkan file objek yang dihasilkan dalam waktu sekitar 5-10 detik pada mesin pengembang .

VS compiler juga tidak terlalu cepat mengkompilasi template sejauh yang saya mengerti, dan karena model inklusi template (Anda praktis memasukkan definisi template di setiap file yang menggunakannya secara tidak langsung dan mungkin instantiate ulang template itu setiap kali Anda memodifikasi sesuatu yang tidak ada hubungannya dengan template itu) Anda bisa memiliki masalah dengan waktu kompilasi (ketika melakukan kompilasi tambahan).

Apa cara Anda menangani waktu kompilasi bertahap (dan tidak hanya) ketika bekerja dengan templat (selain kompiler yang lebih baik / lebih cepat :-)).

Ghita
sumber
1
@RobertHarvey injeksi ketergantungan dibuat menggunakan parameter template. Dalam kode produksi di mana saya instantiate ini saya memiliki waktu kompilasi yang lambat.
Ghita
5
Apakah Anda menggunakan C ++ 11? lihat en.wikipedia.org/wiki/C%2B%2B11#Extern_template
mike30
2
Karena Andrei Alexandrescu telah menulis "Desain C ++ Modern", banyak programmer C ++ berpikir mereka harus menggunakan templat untuk semua dan segalanya dan membiarkan kompilator menangani sebanyak mungkin. Itu biasanya mengarah ke efek yang Anda gambarkan. Sebelumnya (dan saat ini masih untuk programmer menggunakan bahasa lain), itu benar-benar ok untuk tidak menggunakan template dan menangani hal-hal seperti injeksi ketergantungan dengan mekanisme run time, bahkan ketika ini membutuhkan beberapa siklus CPU lebih untuk pengguna akhir (yang hampir tidak akan pernah dia perhatikan) ). Jujur, saya yakin Robert 100% benar dan itulah yang Anda pikirkan.
Doc Brown
1
@ Ghita: IMHO menggunakan pemrograman meta template seringkali hanya bentuk optimasi prematur (dan kadang-kadang hanya berlebihan) - sejauh Anda tidak menulis lib seperti STL dengan persyaratan yang sebanding. Anda menukar beberapa perolehan kinerja untuk waktu kompilasi yang lebih besar, lebih sedikit rawatan dan banyak pesan kesalahan yang sulit dipahami. Menggunakan "templat eksternal" mungkin membantu Anda sekarang dalam jangka pendek, tetapi jika saya berada di posisi Anda, saya juga akan memikirkan perbaikan jangka panjang.
Doc Brown
4
@DocBrown. Sebaliknya, Anda bisa mengatakan menghindari template untuk meningkatkan kinerja build adalah optimasi prematur. Template adalah abstraksi yang ideal untuk banyak masalah.
mike30

Jawaban:

9

Jika parameter template Anda hanya dapat mengasumsikan seperangkat nilai yang terbatas (dan kecil), Anda bisa memindahkan definisinya dalam file sumber, dan menggunakan instantiasi eksplisit .

Misalnya, aaa.hAnda hanya mendeklarasikan fungsi templat fdan g:

template <int n>
int f();

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

Asumsikan nparameter templat hanya boleh 1, 3, 6, dan Tparameter templat hanya bisa int, longdan void *.

Kemudian Anda mendefinisikannya aaa.cppseperti ini:

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

Dengan cara ini kompiler instantiates templat untuk parameter yang diberikan saat kompilasi aaa.cpp. Ketika mengkompilasi kode klien, itu mengasumsikan bahwa definisi ada di suatu tempat, dan penghubung akan mengurusnya.

#include "aaa.h"

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

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

Anda juga dapat secara eksplisit instantiate kelas template. Kekurangannya adalah Anda tidak dapat menggunakan fatau gdengan parameter template lainnya.

#include "aaa.h"

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

hasil dalam

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

Saya menggunakan teknik ini dalam proyek di mana beberapa kelas kompleks bergantung pada set kecil (<10) parameter template integer, dan secara signifikan mengurangi waktu kompilasi (karena kompiler tidak harus menguraikan definisi template kompleks ketika mengkompilasi kode klien) . Tentu saja Anda mungkin mendapatkan peningkatan yang lebih rendah, tergantung pada kode yang sebenarnya.

Claudio
sumber
2

Setelah saya menggunakan solusi aneh untuk masalah yang sama: Termasuk STL memimpin untuk mengkompilasi waktu seperti beberapa detik per file sumber - tidak peduli seberapa kecil itu. Jadi saya memasukkan semua file sumber saya ke dalam satu file master dan waktu kompilasi per file hampir tidak berubah ... yang berarti mempercepat faktor 20+ karena saya hanya memiliki satu file untuk dikompilasi.

Untuk menjaga desain tetap bersih, saya terus mempertahankan makefile, tetapi tidak pernah benar-benar menggunakannya (kecuali untuk memverifikasi masih berfungsi).

maaartinus
sumber
0

Kami biasa menjalankan tugas besar untuk membangun tajuk yang sudah dikompilasi dan templat yang telah dikompilasi dalam semalam, dan hanya membangun terhadap yang berikutnya.

Ti Strga
sumber