2012-03-01 36 views
9

Đó là sự hiểu biết của tôi rằng các mẫu biểu hiện sẽ vỡ trên phạm vi dựa trên C++ 11, như for (auto x : expr) có ẩn auto&& __range = expr trong đó, và điều này sẽ dẫn đến tham chiếu lơ lửng.Các mẫu biểu thức và thay đổi dựa trên trong C++ 11

Có cách nào tạo các lớp mẫu biểu thức để chúng hoạt động chính xác với phạm vi dựa trên, hoặc ít nhất là ném một lỗi biên dịch?

Về cơ bản, tôi muốn ngăn chặn khả năng các mẫu biểu thức sẽ biên dịch chính xác nhưng không thành công khi chạy do các tham chiếu treo lơ lửng. Tôi không nhớ phải bọc các mẫu biểu thức vào một cái gì đó trước khi sử dụng chúng trong một phạm vi dựa trên, miễn là không có lỗi thời gian chạy im lặng nếu người dùng quên bọc các mẫu biểu thức.

+1

'tự động &' trong phạm vi 'for' loop có thể thực sự trở thành một cái gì đó để tự bắn vào chân một cách dễ dàng - tôi vẫn chưa thực sự hiểu chính xác loại phạm vi nào bị ảnh hưởng và tại sao (tham chiếu lvalue để không-const: nguy hiểm, không tham khảo: unproblematic, ???). – Philipp

+1

@Philipp: Không có thứ như "loại phạm vi". Có những loại đơn giản phù hợp với phạm vi "khái niệm". Cụ thể, có một cặp 'begin/end' ghi đè các trình vòng lặp đầu vào trả về. –

+1

Tôi đoán câu trả lời là đảm bảo các mẫu biểu thức không phù hợp với phạm vi "khái niệm", tức là chúng không có 'bắt đầu' và' kết thúc'. – Clinton

Trả lời

2

Có một vài tùy chọn mà tôi có thể nghĩ, mỗi tùy chọn đều có sự xấu xa của riêng mình.

Một tùy chọn hiển nhiên là sử dụng con trỏ (có thể là unique_ptr) thay vì tham chiếu. Tất nhiên, để làm việc này, nó hoặc là yêu cầu phân bổ từ heap, hoặc phân bổ tùy chỉnh. Tôi nghĩ với một người phân bổ tốt, cách tiếp cận này có một số thành tích. Sau đó, một lần nữa, các nhà điều hành quá tải sẽ chỉ nhận được khó chịu.

Cách tiếp cận khác là lưu trữ biểu thức con theo giá trị thay vì tham chiếu const. Hiệu quả của phương pháp này phụ thuộc rất nhiều vào trình biên dịch, nhưng vì cơ bản bạn đang xử lý một loạt các thời gian, tôi sẽ tưởng tượng rằng các trình biên dịch hiện đại có thể tối ưu hóa các bản sao (hoặc ít nhất, nhiều bản sao).

Cách tiếp cận cuối cùng cho phép bạn giữ cùng cấu trúc với mã của mình, nhưng buộc người dùng đánh giá biểu thức. Nó yêu cầu bạn chỉ có một loại có thể lặp lại, là kiểu cơ bản của biểu thức (ví dụ: std::vector<int>). Không có lớp biểu thức nào có các phương thức hoặc hàm beginend được định nghĩa cho chúng, nhưng chỉ nên chuyển đổi thành loại cơ bản. Bằng cách này, mã như for(auto x : expr) sẽ không thành công tại thời điểm biên dịch (vì expr không thể lặp lại), nhưng viết for(auto x : static_cast<vector<int>>(expr)) hoạt động vì biểu thức đã được đánh giá.

Nếu bạn đang hy vọng sử dụng phạm vi dựa trên các vòng để thực hiện các phép toán biểu mẫu, thì bạn có thể cung cấp các phương thức riêng tư hoặc được bảo vệ beginend trong các lớp mẫu biểu thức của bạn. Chỉ cần đảm bảo mỗi lớp mẫu có thể truy cập các phương thức beginend của các lớp mẫu khác. Sẽ không sao trong ngữ cảnh này vì khuôn mẫu biểu thức là một tham số cho hàm, do đó bạn sẽ không phải lo lắng về việc tham khảo các tham chiếu khi viết vòng lặp trong hàm đó.

6

Thường thì không có gì bạn có thể làm về việc này. Nếu bạn đưa ra một biểu thức là phạm vi, nó phải giải quyết cho một cái gì đó sẽ có hiệu lực sau khi khởi tạo câu lệnh for. Và không có cách nào để phát hiện tại thời gian biên dịch mà bất kỳ loại cụ thể nào được suy ra bởi auto.

Sẽ tốt hơn nếu làm cho hệ thống biểu thức của bạn di chuyển nhiều hơn, vì vậy nó không phải giữ tham chiếu. Điều đó sẽ mang lại kết quả an toàn hơn nhiều với auto hơn là cố gắng lưu trữ các tham chiếu đến những thứ có thể đã chết. Nếu việc sao chép các loại không di chuyển làm phiền bạn, thì hãy sống với nó.

+2

Điều đó không giải quyết được vấn đề. Vòng lặp dựa trên dải ô của bạn chứa một '' auto && __ range = listOfInt; ', có thể gây ra vấn đề nếu' listOfInt' thực sự là một giá trị của một số lớp mẫu biểu thức. –

+0

@RichardSmith: Đúng vậy, tôi nghĩ trong trường hợp đó, điều duy nhất người ta có thể làm là giới thiệu một diễn viên rõ ràng hoặc một biến tự động mới. – Philipp

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