2009-07-25 25 views
10

Có phải mẫu Lập trình meta nhanh hơn mã C tương đương không? (Tôi đang nói về hiệu suất thời gian chạy) :)Có phải mẫu Lập trình meta nhanh hơn mã C tương đương không?

+1

Tại sao chọn Downvote? – n00ki3

+1

Bạn đang hỏi gì? –

+2

Điều này đã được giảm giá? Nghiêm túc? Có vẻ như đó là một câu hỏi hoàn hảo cho tôi. (mặc dù tiêu đề và nội dung của câu hỏi dường như hỏi hai câu hỏi khác nhau, có thể là một ý tưởng hay để làm rõ một trong số các câu hỏi bạn quan tâm) – jalf

Trả lời

25

Đầu tiên, tuyên bố từ chối trách nhiệm: Điều tôi nghĩ rằng bạn đang hỏi không chỉ là lập trình meta mẫu, mà còn là lập trình chung. Hai khái niệm có liên quan chặt chẽ và không có định nghĩa chính xác về những khái niệm bao hàm. Nhưng trong ngắn hạn, lập trình meta mẫu về cơ bản là viết một chương trình bằng cách sử dụng các mẫu, được đánh giá tại thời gian biên dịch. (mà làm cho nó hoàn toàn miễn phí trong thời gian chạy. Không có gì xảy ra.Giá trị (hoặc phổ biến hơn, loại) đã được trình biên dịch tính toán, và có sẵn dưới dạng hằng số (hoặc biến const hoặc enum), hoặc như một typedef lồng nhau trong một lớp (nếu bạn đã sử dụng nó để "tính toán" một loại).

Lập trình chung đang sử dụng mẫu và khi cần thiết, lập trình meta mẫu, để tạo mã chung hoạt động như nhau (và không bị mất hiệu năng), với tất cả và bất kỳ loại nào. Tôi sẽ sử dụng các ví dụ về cả hai điều sau đây.

Việc sử dụng phổ biến cho lập trình meta mẫu là cho phép các loại được sử dụng trong lập trình chung, ngay cả khi chúng không được thiết kế cho nó. Kể từ khi lập trình meta mẫu kỹ thuật diễn ra hoàn toàn vào thời gian biên dịch, câu hỏi của bạn có liên quan hơn một chút để lập trình chung, vẫn diễn ra trong thời gian chạy, nhưng hiệu quả vì nó có thể chuyên biệt cho các loại chính xác được sử dụng tại thời gian biên dịch.

Dù sao ...


Phụ thuộc vào cách bạn định nghĩa "mã C tương đương".

Bí quyết về lập trình meta mẫu (hoặc chương trình chung nói chung) là nó cho phép tính toán nhiều thời gian để biên dịch và cho phép mã linh hoạt, tham số hiệu quả như các giá trị được mã hóa.

Mã được hiển thị here ví dụ tính một số trong chuỗi mã hóa tại thời gian biên dịch.

Mã C++ 'unsigned long fib11 = fibonacci<11uL>::value', dựa trên mẫu meta được xác định trong liên kết đó và có hiệu quả như mã C 'unsigned long fib11 = 89uL'. Các mẫu được đánh giá tại thời gian biên dịch, sinh ra một hằng số có thể được gán cho một biến. Vì vậy, trong thời gian chạy, mã thực sự giống với một nhiệm vụ đơn giản.

Vì vậy, nếu đó là "mã C tương đương", hiệu suất là như nhau. Nếu mã C tương đương là "một chương trình có thể tính toán số lượng tùy ý, được áp dụng để tìm số thứ 11 trong chuỗi", thì phiên bản C sẽ chậm hơn nhiều, vì nó phải được thực hiện như một hàm, tính toán giá trị khi chạy. Nhưng đây là "mã C tương đương" theo nghĩa là chương trình C thể hiện tính linh hoạt tương tự (nó không chỉ là hằng số được mã hóa cứng, mà là một hàm thực tế có thể trả về số bất kỳ số nào trong chuỗi mã lực).

Tất nhiên, điều này thường không hữu ích. Nhưng nó là khá nhiều ví dụ kinh điển về lập trình meta mẫu.

Một ví dụ thực tế hơn về lập trình chung là sắp xếp.

Trong C, bạn có chức năng thư viện chuẩn qsort lấy một mảng và một con trỏ hàm so sánh. Các cuộc gọi đến con trỏ chức năng này không thể được inlined (ngoại trừ trong trường hợp tầm thường), bởi vì tại thời gian biên dịch, nó không được biết chức năng nào sẽ được gọi.

Tất nhiên, thay thế là chức năng phân loại viết tay được thiết kế cho kiểu dữ liệu cụ thể của bạn.

Trong C++, tương đương với mẫu chức năng std::sort.Nó cũng có một so sánh, nhưng thay vì đây là một con trỏ hàm, nó là một đối tượng hàm, trông như thế này:

struct MyComp { 
    bool operator()(const MyType& lhs, const MyType& rhs) { 
    // return true if lhs < rhs, however this operation is defined for MyType objects 
    } 
}; 

và điều này có thể được inlined. Hàm std::sort được chuyển qua một đối số mẫu, do đó, nó biết loại so sánh chính xác và do đó, nó biết rằng hàm so sánh không chỉ là một con trỏ hàm không xác định, mà là MyComp::operator().

Kết quả cuối cùng là hàm C++ std::sortchính xác hiệu quả như việc triển khai mã tay của bạn trong C của cùng một thuật toán sắp xếp.

Vì vậy, một lần nữa, nếu đó là "mã C tương đương", thì hiệu suất là như nhau. Nhưng nếu "mã C tương đương" là "hàm phân loại tổng quát có thể được áp dụng cho bất kỳ loại nào và cho phép các trình so sánh do người dùng xác định", thì phiên bản lập trình chung trong C++ hiệu quả hơn rất nhiều.

Đó thực sự là mẹo. Lập trình meta và lập trình meta mẫu không phải là "nhanh hơn C". Họ là những phương pháp để đạt chung, tái sử dụng đang đó là nhanh như handcoded, và mã hóa cứng C

Đó là một cách để có được tốt nhất của cả hai thế giới. Hiệu suất của các thuật toán mã hóa cứng, và tính linh hoạt và khả năng tái sử dụng của các thuật toán chung, được tham số hoá.

+0

jalf Tôi đã sử dụng ví dụ sắp xếp trong câu trả lời của mình, vì vậy +1 cho chiến binh C++: D – AraK

+1

Um, tôi nghĩ có sự khác biệt lớn giữa lập trình chung và TMP, nhưng tôi hiểu rằng bạn đã đưa vào ví dụ GP để làm cho vấn đề của bạn. Tuy nhiên, tôi sẽ bỏ lỡ một gợi ý rằng bộ so sánh không phải là TMP. – sbi

+0

điểm công bằng. Tôi đã thêm một chút giải thích vào đầu những gì GP và TMP, và đề cập rằng ví dụ sắp xếp thường sẽ được coi là GP, nhưng nghĩ rằng tôi sẽ để nó ở đó. – jalf

11

Mẫu Lập trình meta (TMP) là 'chạy' tại thời gian biên dịch, vì vậy nó không thực sự so sánh táo với táo khi so sánh nó với mã C/C++ bình thường.

Nhưng, nếu bạn có thứ gì đó được đánh giá bởi TMP, thì không có chi phí thời gian chạy nào cả.

1

Câu trả lời là tùy thuộc.

Lập trình meta mẫu có thể được sử dụng để dễ dàng viết các trình phân tích ngôn ngữ gốc đệ quy và có thể không hiệu quả so với chương trình C được tạo cẩn thận hoặc triển khai dựa trên bảng (ví dụ: flex/bison/yacc).

Mặt khác, bạn có thể viết các metaprogram tạo ra các vòng chưa được kiểm soát có thể hiệu quả hơn so với việc thực hiện C thông thường sử dụng vòng lặp.

Lợi ích chính là metaprogram cho phép lập trình viên làm nhiều hơn với ít mã hơn.

Nhược điểm là nó cũng cung cấp cho bạn một khẩu súng gatling để bắn mình vào chân với.

1

Lập trình meta mẫu có thể được coi là thực thi biên dịch.

Thời gian biên dịch sẽ mất nhiều thời gian để biên dịch mã của bạn vì nó phải biên dịch và sau đó thực thi các mẫu, tạo mã, sau đó biên dịch lại.

Chi phí thời gian chạy mà tôi không chắc chắn, nó không được nhiều hơn nếu bạn tự viết mã C trong trường hợp tôi sẽ tưởng tượng.

1

Tôi đã làm việc trên một dự án mà một lập trình viên khác đã thử nghiệm lập trình meta. Điều đó thật tồi tệ. Đó là một cơn đau đầu hoàn toàn. Tôi là một lập trình viên trung bình với rất nhiều kinh nghiệm về C++, và cố gắng nghĩ ra cái quái gì mà họ đang cố gắng làm nhiều hơn thời gian nếu họ viết nó ngay lập tức để bắt đầu.

Tôi đã chống lại lập trình meta C++ vì trải nghiệm này.

Tôi tin tưởng rằng mã tốt nhất dễ đọc nhất bởi nhà phát triển trung bình. Đó là khả năng đọc của phần mềm là ưu tiên số 1. Tôi có thể làm bất cứ điều gì làm việc bằng cách sử dụng bất kỳ ngôn ngữ nào ... nhưng kỹ năng đó là làm cho nó dễ đọc và dễ dàng làm việc cho người tiếp theo trong dự án. C++ MetaProgramming không truyền qua được.

+3

Có lẽ vấn đề là người liên kết của bạn không ghi đầy đủ những gì mã lập trình meta của anh ấy đang làm? Hoặc có lẽ anh ta không giỏi viết mã dễ hiểu. Trong mọi trường hợp, tôi không chắc là công bằng khi lên án toàn bộ kỹ thuật dựa trên một trải nghiệm với một codebase. –

+0

Tôi đồng ý với Jeremy. Có lẽ đồng nghiệp của bạn không giỏi viết mã, hoặc làm như vậy một cách rõ ràng, nhưng tôi không nghĩ bạn không đọc nó khiến nó trở nên tệ hại. Có lẽ nó * đã được viết tốt và bạn chỉ cần thêm kinh nghiệm với các mẫu? – GManNickG

+0

Có lẽ mã tự nó không cho vay tự nó được lập trình meta! – AraK

0

Tôi không nghĩ có bất kỳ quảng cáo thổi phồng, nhưng một câu trả lời rõ ràng và đơn giản về các mẫu được đưa ra bởi C++ Hỏi đáp: https://isocpp.org/wiki/faq/templates#overview-templates

Về câu hỏi ban đầu: nó không thể trả lời, vì những điều đó là không thể so sánh.

4

Nếu bạn có nghĩa là mã có thể sử dụng lại, thì có mà không nghi ngờ gì. Metaprogramming là một cách tuyệt vời để tạo ra các thư viện, không phải mã máy khách. Mã khách hàng không phải là chung chung, nó được viết để làm những việc cụ thể.

Ví dụ: xem qsort từ thư viện chuẩn C và tiêu chuẩn C++ sắp xếp. Đây là cách qsort công trình:

int compare(const void* a, const void* b) 
{ 
    return (*(int*)a > *(int*)b); 
} 

int main() 
{ 
    int data[5] = {5, 4, 3, 2, 1}; 

    qsort(data, 5, sizeof(int), compare); 
} 

Bây giờ nhìn vào loại:

struct compare 
{ 
    bool operator()(int a, int b) 
    { return a < b; } 
}; 

int main() 
{ 
    int data[5] = {5, 4, 3, 2, 1}; 
    std::sort(data, data+5, compare()); 
} 

loại là sạch hơn, an toàn hơn và nhiều hơn nữa hiệu quả vì chức năng so sánh được inlined bên trong sắp xếp. Đó là lợi ích của lập trình meta trong quan điểm của tôi, bạn viết mã generic, nhưng trình biên dịch mã như sản phẩm Mặt mã một!


Một nơi mà tôi tìm thấy Lập trình meta rất đẹp là khi bạn viết một thư viện như boost :: tinh thần hoặc đẩy mạnh :: xpressive, với tinh thần bạn có thể viết EBNF bên trong C++ và để cho các biên dịch kiểm tra cú pháp EBNF cho bạn và với xpressive bạn có thể viết regex và để trình biên dịch kiểm tra cú pháp regex cho bạn!


Tôi không chắc liệu người hỏi có nghĩa là bằng cách tính giá trị tại thời điểm biên dịch của TMP hay không. Đây là một ví dụ tôi đã viết sử dụng tăng :)

unsigned long greatestCommonDivisor = boost::math::static_gcd<25657, 54887524>::value; 

gì mà bạn từng làm với C bạn không thể bắt chước các mã trên, về cơ bản bạn phải tay tính toán sau đó nó gán kết quả cho greatestCommonDivisor!

+0

Đây không phải là lập trình meta. Đây chỉ là các mẫu. – GManNickG

+0

Vâng, đây là tính toán loại tại thời gian biên dịch :) nó không phải là tính toán số. – AraK

+0

Về mặt kỹ thuật, nó thậm chí không cần tính toán loại ... – GManNickG

0

Lập trình meta mẫu không cung cấp cho bạn bất kỳ quyền hạn ma thuật nào về hiệu suất. Về cơ bản nó là một bộ tiền xử lý rất tinh vi; bạn luôn có thể viết tương đương trong C hoặc C++, nó chỉ có thể đưa bạn một thời gian rất dài.

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