2013-09-27 77 views
18

Tôi đang làm việc trên cơ sở hạ tầng phần mềm quy mô lớn trong C++ 11, sử dụng rộng rãi các mẫu variadic. Câu hỏi của tôi là như sau: khả năng mở rộng của phương pháp này là gì? Đầu tiên, có giới hạn trên về số lượng các đối số mà các mẫu variadic có thể thực hiện không? Thứ hai, mã bloat là một vấn đề lớn với các trình biên dịch hiện đại khi nhiều đối số được sử dụng (và, bằng cách mở rộng, nhiều kết hợp của các đối số này có thể mang lại nhiều triển khai khác nhau của các phương thức khuôn mẫu)?Khả năng mở rộng của các mẫu variadic

+10

Về mặt lý thuyết không có giới hạn, nhưng rõ ràng, có một số giới hạn trong thực tế, được quyết định bởi một số tài nguyên hạn chế như RAM. Nếu bạn đến một điểm mà giới hạn đó quan trọng, bạn có thể có vấn đề lớn hơn, vì vậy tôi sẽ không lo lắng về điều đó. –

+3

Câu hỏi thứ hai của bạn khó trả lời, bởi vì nó phụ thuộc nhiều vào phần còn lại của mã hơn là chính xác có bao nhiêu đối số mẫu. Nếu bạn sử dụng nhiều đối số mẫu để tính thời gian biên dịch công cụ, có thể không có bất kỳ mã nào được tạo. Nếu không, nếu mã đang được tạo, số lượng instantiations sẽ là một yếu tố nhân. Điều này không khác với các mẫu không phải là biến thể. –

+12

Phụ lục B (Số lượng thực hiện), tiêu chuẩn C++ 11 không nói cụ thể về mẫu * variadic *, nhưng nó đề xuất ít nhất 256 tham số hàm và tham số mẫu 1024. Tuy nhiên, bạn có thể gặp phải các vấn đề trước đó khi tên bị xé của bạn quá dài. – Oberon

Trả lời

10

Tôi nghĩ rằng tôi muốn tìm hiểu xem có giới hạn về số tham số mẫu cho trình biên dịch cụ thể của tôi không (g ++ 4.8.1 trên Linux). Tôi đã sử dụng trường hợp kiểm tra sau:

template <int I> 
struct this_is_a_ridiculously_long_struct_name_youd_never_use_in_real_life {}; 

template <int Depth, typename... T> 
struct A 
{ 
    using e = this_is_a_ridiculously_long_struct_name_youd_never_use_in_real_life<Depth>; 

    A() {}; 

    A<Depth - 1, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, T...> a; 
}; 

template <typename... T> 
struct A<0, T...> 
{ 
}; 

int main() 
{ 
    A<899> a; 
} 

Giới hạn chiều sâu đệ quy mẫu mặc định là 900 trong g ++, do đó thông số 899 bạn thấy. Tên cấu trúc vô cùng dài được sử dụng để xem liệu tôi có thể tạo ra bất kỳ ký hiệu nào quá lớn để trình liên kết có thể xử lý được hay không - nhiều hơn về điều này trong giây lát.

Trong trường hợp bạn không thể nhìn thấy những gì đang xảy ra trong trường hợp thử nghiệm, về cơ bản, mỗi lần tạo A sẽ tạo biến thành viên có thêm 20 tham số mẫu bổ sung. Chuyên môn từng phần được sử dụng để ngăn chặn đệ quy. Đến cuối, A<0, ...> có một nơi nào đó trong khu vực của 18.000 thông số mẫu.

Điều tôi thấy là g + + xử lý việc này tốt. Phải mất một thời gian để suy nghĩ về nó, và sử dụng một chút công bằng của bộ nhớ, nhưng tôi đã không thể làm cho nó thất bại chỉ đơn giản bằng cách tăng số lượng các tham số mẫu. Clang 3.1 cũng xử lý điều này mà không có bất kỳ vấn đề nào khi độ sâu đệ quy mẫu được thiết lập đầy đủ (tức là 900).

Hơn nữa, mặc dù tên biểu tượng bị cắt xén thực sự trở nên rất lớn, tôi không thể phá vỡ hoặc nm hoặc ld sử dụng chúng. (Cần lưu ý rằng lược đồ xâu chuỗi Linux/Itanium sử dụng thay thế để các tham số mẫu lặp lại cùng loại không lặp lại toàn bộ tên kiểu, mà thay vào đó được đánh dấu S0, S1 v.v.) tăng bất kỳ giới hạn nào về độ dài biểu tượng ELF, nhưng có lẽ một người khác biết liệu giới hạn đó có tồn tại hay không.

Tóm lại, đối với g ++ và clang trên Linux ít nhất, dường như không có giới hạn thực tế về số tham số mẫu.

Đối với phần thứ hai của câu hỏi của bạn, liên quan đến mã bloat, rất khó để nói, đặc biệt khi tối ưu hóa trình biên dịch được tham gia. Thật dễ dàng để làm đệ quy với các mẫu variadic, nhưng sau đó nó dễ dàng cho trình biên dịch để loại bỏ các loại trung gian quá. Tôi chỉ có thể đề nghị thử và xem.

+0

Số đối số mẫu mà tôi đang sử dụng (trong mã được tạo) phụ thuộc vào khách hàng và do đó không có giới hạn. Vì vậy, câu trả lời của tôi đề xuất sử dụng boost :: mpl để tránh giới hạn này. –

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