2009-02-24 71 views
22

Mẫu C++ đã là một phước lành trong công việc hàng ngày của tôi vì sức mạnh của nó. Nhưng người ta không thể bỏ qua (rất rất rất rất dài) thời gian biên dịch kết quả từ việc sử dụng nhiều mẫu (hello meta-programming và Boost libraries). Tôi đã đọc và thử khá nhiều khả năng sắp xếp lại và sửa đổi mã mẫu theo cách thủ công để làm cho nó biên dịch nhanh nhất có thể.Có các trình biên dịch C++ được tối ưu hóa để sử dụng mẫu không?

Bây giờ tôi tự hỏi nếu có bất kỳ trình biên dịch C++ nào cố gắng và giảm thiểu thời gian cần thiết để diễn giải các lớp mẫu. Tôi có thể sai, nhưng tôi cảm thấy rằng các trình biên dịch tôi biết chỉ có thêm bản dịch mẫu cho các phiên bản trước của họ.

Câu hỏi của tôi là:

  • là C++ mẫu mã rất khó khăn để giải thích rằng không có nhiều để tối ưu hóa? (tôi rất nghi ngờ rằng)
  • Có trình biên dịch C++ nào thực sự tối ưu hóa giải thích "mẫu C++" không?
  • Có dự án nào để phát triển một thế hệ mới của trình biên dịch C++ để tối ưu hóa điều này không?
  • Nếu bạn tham gia vào một dự án như vậy, nguyên tắc của bạn sẽ là gì?
+0

Tôi muốn các nhà phát triển trình biên dịch tập trung vào tối ưu hóa mã được tạo và tận dụng lợi thế của tính song song (SMP, distcc, Xoreax IncrediBuild, v.v.) để tăng tốc các bản dựng. – bk1e

+4

Tại sao không yêu cầu họ làm việc trên cả hai vấn đề? Lợi ích tôi mong đợi từ một trình biên dịch C++ đã được tối ưu hóa cho các mẫu cao hơn nhiều so với cái tôi nhận được từ việc sử dụng song song (và tôi đã làm), trừ khi bạn được bao quanh bởi một máy tính đang chờ bạn biên dịch mã (i don ' t)! –

Trả lời

4

Dường như g ++ 4.5 đã đạt được tiến bộ to lớn đối với các mẫu. Dưới đây là hai thay đổi không thể tránh khỏi.

  • "Khi in tên chuyên môn mẫu lớp, G ++ giờ sẽ bỏ qua bất kỳ đối số mẫu nào đến từ đối số mẫu mặc định". Điều đó có thể được coi là một sửa đổi tinh tế, nhưng nó sẽ có tác động rất lớn đến sự phát triển với các mẫu C++ (bao giờ nghe nói về các thông báo lỗi không thể đọc được ...? Không còn nữa!)

  • "Thời gian biên dịch cho mã sử dụng mẫu giờ đây sẽ được chia tỷ lệ tuyến tính với số lần instantiations thay vì theo phương thức bậc hai." Điều này sẽ làm suy yếu nghiêm trọng các đối số thời gian biên dịch đối với việc sử dụng các mẫu C++.

Xem trên gnu site cho thông tin đầy đủ

Trên thực tế, tôi đang đã tự hỏi liệu có vẫn là những vấn đề với C++ mẫu! Mmm, vâng, có, nhưng hãy tập trung vào mặt tươi sáng ngay bây giờ!

2

Đó không phải là câu trả lời bạn muốn nhưng Walter Bright là nhà phát triển chính của trình biên dịch C++ bản địa đầu tiên và trình biên dịch C++ được tối ưu hóa. Sau khi tất cả những gì ông đã viết ngôn ngữ lập trình riêng của mình được gọi là D. Đó là cơ bản một sự cải tiến trên C + + và đối phó với các mẫu tốt hơn.

Tôi không biết bất kỳ trình biên dịch C++ nào được tối ưu hóa để sử dụng mẫu.

+0

IIRC ai đó đã làm một 50 ngữ pháp sản xuất với Boost :: Spirit (một trình tạo phân tích cú pháp chương trình meta) và mất 17 giờ để biên dịch. Tôi có 250 ngữ pháp sản xuất biên dịch bằng cách sử dụng một D tương đương trong 7 * phút * – BCS

+0

Bây giờ đó là loại đạt được tôi đang mong đợi! Nhưng tôi không thể thay đổi mọi mã hiện tại thành ngôn ngữ D! –

0

Tôi nghĩ bản thân các mẫu không quá phức tạp. Chúng ta sẽ thấy khi các khái niệm được giới thiệu trong C++ 0x, vv, nhưng hiện tại, các mẫu chỉ là (gần như) là các macro, vì vậy vấn đề thực sự không phải là nếu bạn đã tối ưu hóa các trình biên dịch C++ cho các khuôn mẫu. Vấn đề là các mẫu tạo ra một lượng lớn mã như vậy khi biên dịch, làm cho việc biên dịch chậm hơn.

+0

Bạn có thể xây dựng dựa trên những gì bạn tin rằng việc biên dịch chậm hơn không? Cá nhân tôi sử dụng các mẫu như một cách để cô lập sự phát triển của các lớp trong các dự án của tôi. Nếu chỉ có một dự án, tôi có thể làm điều tương tự mà không cần bất kỳ mẫu nào. Nhưng có rất nhiều dự án do đó nhiều mẫu! –

+0

Benoît, biên dịch ** là ** chậm hơn với các mẫu. Lưu ý rằng khi bạn sử dụng, giả sử, vector và gọi một số hàm trên đó, trình biên dịch sẽ lấy mã templated và biên dịch nó cho kiểu int. Nếu bạn sử dụng, ví dụ, vector , giống nhau. Tuy nhiên tốc độ biên dịch thông thường thường là ... –

+0

... mối quan tâm thứ hai, với nhiều mẫu, bạn có thể phát triển một giải pháp sạch hơn cho một vấn đề, hoặc thậm chí giải quyết những thứ mà bạn không thể làm mà không có mẫu. Tóm lại: các mẫu biên dịch chậm hơn, nhưng chúng là một sự trừu tượng quan trọng trong C++. –

1

Hãy thử Incredibuild. Nó giảm đáng kể thời gian biên dịch/xây dựng.

Sản phẩm này về cơ bản cho phép Visual C++ xây dựng trên nhiều máy trong tổ chức của bạn bằng cách tận dụng các chu kỳ nhàn rỗi. Tôi đã sử dụng Incredibuild trên các dự án lớn (500 kloc) với rất nhiều mẫu mã và có tốc độ tốt trong thời gian xây dựng.

9

Đây thực sự không phải là câu trả lời cho câu hỏi của bạn. Đó là một quan sát phụ.

Tôi cũng không phải là luật sư ngôn ngữ C++, vì vậy tôi có thể thoát khỏi cơ sở bằng một số chi tiết.

Nhưng, ý tưởng thô phải chính xác.

Lý do chính mà trình biên dịch C++ mất một thời gian dài để biên dịch mẫu meta-chương trình là do cách các siêu mẫu được chỉ định.

Chúng không được chỉ định trực tiếp dưới dạng mã mà bạn muốn trình biên dịch chạy lúc biên dịch. Lấy ví dụ về tính toán độ dài của một danh sách loại.

Nếu bạn có thể viết mã như thế này:

compile_time size_t GetLength(TypeList * pTypeList) 
{ 
    return DoGetLength(pTypeList, 0); 
} 

compile_time size_t DoGetLength(TypeList * pTypeList, size_t currentLength) 
{ 
    if (pTypeList) 
    { 
     return DoGetLength(pTypeList->Next, ++currentLength); 
    } 
    else 
    { 
     return currentLength; 
    } 
} 

Đó là một số cách biên dịch riêng rẽ từ mã nơi nó được sử dụng, và được tiếp xúc với ngôn ngữ thông qua một số cú pháp, sau đó trình biên dịch sẽ có thể thực hiện nó rất nhanh.

Nó sẽ chỉ là một cuộc gọi hàm đệ quy đơn giản.

Có thể thiết kế ngôn ngữ cho phép những thứ đó. Hầu hết những người làm điều này (như lisp) được gõ động, nhưng nó có thể làm với gõ tĩnh. Tuy nhiên, nó không bao giờ có thể là một cái gì đó bạn sẽ thấy thực hiện trong C + +.

Các vấn đề trong C++, tuy nhiên, được rằng mã được viết như sau:

template <typename First, typename Second> 
struct TypeList 
{ 
    typedef First Head; 
    typedef Second Tail; 
}; 

template <> 
struct ListSize<NullType> 
{ 
    enum { size = 0 }; 
}; 

template <typename Head, typename Tail> 
struct ListSize<TypeList<Head, Tail> > 
{ 
    enum { size = 1 + ListSize<Tail>::size }; 
}; 

Để cho trình biên dịch để "thực thi" meta-chương trình nó phải:

  1. Thi công biểu đồ phụ thuộc cho các giá trị ban đầu của giá trị enum "kích thước"
  2. Tạo kiểu mẫu cho mỗi cạnh trong biểu đồ
  3. Liên kết tất cả ký hiệu được tham chiếu bởi mỗi mẫu loại
  4. topology với sắp xếp các đồ thị phụ thuộc
  5. Traverse đồ thị và đánh giá hằng

Đây là đắt hơn nhiều hơn là chỉ đơn giản là chạy một O (N) thuật toán đệ quy.

Trường hợp xấu nhất sẽ giống như O (N * M * L), với N bằng độ dài của danh sách, M là mức phạm vi lồng nhau, và L là số biểu tượng trong mỗi phạm vi.

Lời khuyên của tôi là giảm thiểu số lượng lập trình meta mẫu C++ mà bạn sử dụng.

+0

+1. Tôi thích ví dụ của bạn. Đó là chính xác những gì tôi có trong tâm trí. Mẫu meta-lập trình là "chỉ" kịch bản với trình biên dịch như một thông dịch viên. Mặc dù nó không thể được xử lý trong O (N), tôi không tin rằng chúng tôi sẽ nhận được bất cứ nơi nào gần với kịch bản trường hợp xấu nhất của bạn ... –

14

Tôi mong rằng việc biên dịch mã templated sẽ tăng tốc với việc có các tham chiếu mẫu Denisdic/rvalue. Hôm nay, nếu chúng ta muốn viết mã mẫu thực hiện điều gì đó trong thời gian biên dịch, chúng ta lạm dụng các quy tắc của ngôn ngữ. Chúng tôi tạo ra hàng chục tình trạng quá tải và chuyên môn hóa mẫu dẫn đến những gì chúng tôi muốn, nhưng không phải theo cách nói với trình biên dịch ý định của chúng tôi. Vì vậy, có rất ít để tắt cho trình biên dịch tại thời gian xây dựng. Xem Motivation for variadic templates

Có các dự án phát triển thế hệ mới của trình biên dịch C++ nào sẽ tối ưu hóa điều này không?

Có, có CLang là giao diện ngôn ngữ C cho cơ sở hạ tầng trình biên dịch LLVM. Cả CLang và LLVM đều được mã hóa bằng C++. Trong số các nhà phát triển của CLang là Douglas Gregor, tác giả của một số đề xuất ngôn ngữ C++ 1x như mẫu và khái niệm variadic. Để tham khảo, xem thử nghiệm này bởi Douglas Gregor của vang chống lại GCC

http://www.freeimagehosting.net/uploads/a2e6f1dc27.png

Dưới đây là một số kết quả thực hiện nhanh chóng-n-bẩn cho mẫu instantiation trong Clang và GCC 4.2.Bài kiểm tra rất đơn giản: đo thời gian biên dịch (chỉ -fsyntax) cho một đơn vị dịch tính tính số Fibonacci thứ N thông qua một bản mẫu meta. Clang xuất hiện để mở rộng tuyến tính (hoặc gần với nó) với số lượng instantiations. Và, mặc dù bạn không thể nhìn thấy nó trong bảng xếp hạng, Clang nhanh hơn 2 lần so với GCC ngay từ đầu (Fibonacci<100>).

CLang vẫn ở trong số early days nhưng tôi nghĩ rằng nó có cơ hội tốt để trở thành Trình biên dịch C++ tuyệt vời.

7

Các Vấn đề chính với các mẫu như sau:

Bạn có thể không (thường) tách các định nghĩa của lớp mẫu của bạn từ khai của nó và đặt nó bên trong một file cpp.

Hậu quả: Everyting nằm trong tệp tiêu đề. Bất cứ khi nào bạn bao gồm tiêu đề, bạn bao gồm toàn bộ nhiều mã trong hoàn cảnh bình thường sẽ được phân tách thành các tệp .cpp và được biên dịch riêng biệt. Mỗi đơn vị biên dịch bao gồm một vài tiêu đề, và như vậy, với các mẫu, mỗi đơn vị biên dịch chứa nhiều mã hoặc gần như tất cả dự án của bạn, thông qua các tiêu đề được bao gồm.

Nếu đó là vấn đề của bạn, sau đó nhìn ở đây, tại một câu hỏi liên quan:

Nó có một very good answer, mà giải quyết vấn đề mà.

Về cơ bản, nó liên quan đến việc khởi tạo các mẫu mà bạn cần một lần và biên dịch chúng thành tệp đối tượng. Sau đó, bạn có thể liên kết với nó và bạn không phải bao gồm mã đó ở mọi nơi. Nó được tách thành một tệp đối tượng được biên dịch. Lưu ý: Điều đó chỉ có ý nghĩa nếu bạn chỉ sử dụng một vài loại mẫu đã được khởi tạo của mình (ví dụ: bạn chỉ cần MyType<int>MyType<double> trong chương trình của mình).

Sử dụng cờ g++-fno-implicit-templates.

Đó là kỹ thuật rất hữu ích mà tôi nghĩ rằng nó nên được đưa vào ++ faq C: [35.12] Why can't I separate the definition of my templates class from it's declaration and put it inside a .cpp file?

+0

Tất nhiên bạn là đúng. Mọi thứ đều có trong tệp tiêu đề. Nhưng điều đó không có nghĩa là nó không thể nằm trong các tệp tiêu đề được phân tách. Tôi làm việc hàng ngày với các lớp mẫu được phân tách trong hai tập hợp các tệp tiêu đề: khai báo và triển khai ... –

+0

... Tại sao không thêm một số khác cho khai báo chuyển tiếp? Dù sao, các tệp cpp thực tế chứa cả các tham số mẫu và triển khai thực hiện. Nó hoạt động rất tốt, nhưng thật không may, nó không giúp đỡ nhiều như xa như tốc độ biên dịch là có liên quan. –

+0

Hãy bình luận đầu tiên của bạn: Chỉ cần đặt các khai báo và triển khai mẫu vào các tệp tiêu đề riêng biệt sẽ không giúp tốc độ biên dịch. Bạn vẫn phải bao gồm cả hai cho mỗi đơn vị biên dịch, nếu bạn không sử dụng thủ thuật được mô tả trong câu trả lời của tôi. – Frank

2

Các gold linker có thể giúp làm giảm liên kết thời gian khoảng 5 lần, có thể làm giảm thời gian biên dịch tổng thể. Nó đặc biệt hữu ích vì liên kết không thể song song theo cùng cách mà trình biên dịch có thể.

(Không phải câu trả lời trực tiếp, nhưng hy vọng điều này hữu ích).

Các vấn đề liên quan