Có hai phần cho câu trả lời. Khả năng tương thích ở cấp trình biên dịch và khả năng tương thích ở cấp trình liên kết. Hãy bắt đầu với cái trước.
giả sử tất cả các tiêu đề được viết bằng C ++ 11
Sử dụng cùng một trình biên dịch có nghĩa là cùng một tiêu đề thư viện tiêu chuẩn và các tệp nguồn (các tệp liên kết với trình biên dịch) sẽ được sử dụng bất kể tiêu chuẩn C ++ đích. Do đó, các tệp tiêu đề của thư viện chuẩn được viết để tương thích với tất cả các phiên bản C ++ được hỗ trợ bởi trình biên dịch.
Điều đó nói rằng, nếu các tùy chọn trình biên dịch được sử dụng để biên dịch một đơn vị dịch chỉ định một tiêu chuẩn C ++ cụ thể, thì bất kỳ tính năng nào chỉ có sẵn trong các tiêu chuẩn mới hơn sẽ không thể truy cập được. Điều này được thực hiện bằng cách sử dụng __cplusplus
chỉ thị. Xem tệp nguồn vectơ để biết ví dụ thú vị về cách nó được sử dụng. Tương tự, trình biên dịch sẽ từ chối bất kỳ tính năng cú pháp nào được cung cấp bởi các phiên bản mới hơn của tiêu chuẩn.
Tất cả điều đó có nghĩa là giả định của bạn chỉ có thể áp dụng cho các tệp tiêu đề bạn đã viết. Các tệp tiêu đề này có thể gây ra sự không tương thích khi được đưa vào các đơn vị dịch khác nhau nhắm mục tiêu các tiêu chuẩn C ++ khác nhau. Điều này được thảo luận trong Phụ lục C của tiêu chuẩn C ++. Có 4 mệnh đề, tôi sẽ chỉ thảo luận về mệnh đề đầu tiên, và đề cập ngắn gọn đến các mệnh đề còn lại.
C.3.1 Khoản 2: các quy ước từ vựng
Dấu ngoặc kép đơn phân tách một ký tự theo nghĩa đen trong C ++ 11, trong khi chúng là dấu phân tách chữ số trong C ++ 14 và C ++ 17. Giả sử bạn có định nghĩa macro sau trong một trong các tệp tiêu đề C ++ 11 thuần túy:
#define M(x, ...) __VA_ARGS__
// Maybe defined as a field in a template or a type.
int x[2] = { M(1'2,3'4) };
Hãy xem xét hai đơn vị dịch bao gồm tệp tiêu đề, nhưng nhắm mục tiêu C ++ 11 và C ++ 14, tương ứng. Khi nhắm mục tiêu C ++ 11, dấu phẩy trong dấu ngoặc kép không được coi là dấu phân cách tham số; chỉ có một tham số. Do đó, mã sẽ tương đương với:
int x[2] = { 0 }; // C++11
Mặt khác, khi nhắm mục tiêu C ++ 14, các dấu nháy đơn được hiểu là dấu phân tách chữ số. Do đó, mã sẽ tương đương với:
int x[2] = { 34, 0 }; // C++14 and C++17
Vấn đề ở đây là việc sử dụng các dấu ngoặc kép trong một trong các tệp tiêu đề C ++ 11 thuần túy có thể dẫn đến các lỗi đáng ngạc nhiên trong các đơn vị dịch nhắm mục tiêu C ++ 14/17. Do đó, ngay cả khi tệp tiêu đề được viết bằng C ++ 11, nó phải được viết cẩn thận để đảm bảo rằng nó tương thích với các phiên bản sau của tiêu chuẩn. Các __cplusplus
chỉ thị có thể hữu ích ở đây.
Ba điều khoản khác từ tiêu chuẩn bao gồm:
C.3.2 Khoản 3: các khái niệm cơ bản
Thay đổi : Bộ phân bổ giao dịch thông thường (không phải vị trí) mới
Cơ sở lý luận : Cần thiết cho phân bổ quy mô.
Ảnh hưởng đến tính năng gốc : Mã C ++ 2011 hợp lệ có thể khai báo một hàm phân bổ vị trí toàn cầu và hàm phân bổ giao dịch như sau:
void operator new(std::size_t, std::size_t);
void operator delete(void*, std::size_t) noexcept;
Tuy nhiên, trong tiêu chuẩn này, tuyên bố xóa toán tử có thể khớp với xóa toán tử thông thường (không theo vị trí) được xác định trước (3.7.4). Nếu vậy, chương trình không hợp lệ, vì nó dành cho các hàm cấp phát thành viên lớp và các hàm phân bổ đối phó (5.3.4).
C.3.3 Khoản 7: khai báo
Thay đổi : hàm thành viên không tĩnh của constexpr không ngầm định là hàm thành viên const.
Cơ sở lý luận : Cần thiết để cho phép các hàm thành viên constexpr thay đổi đối tượng.
Ảnh hưởng đến tính năng gốc : Mã C ++ 2011 hợp lệ có thể không biên dịch được trong tiêu chuẩn này.
Ví dụ: mã sau hợp lệ trong C ++ 2011 nhưng không hợp lệ trong tiêu chuẩn này vì nó khai báo cùng một hàm thành viên hai lần với các kiểu trả về khác nhau:
struct S {
constexpr const int &f();
int &f();
};
C.3.4 Điều 27: thư viện đầu vào / đầu ra
Thay đổi : được không được xác định.
Cơ sở lý luận : Sử dụng được coi là nguy hiểm.
Ảnh hưởng đến tính năng gốc : Mã C ++ 2011 hợp lệ sử dụng hàm get có thể không biên dịch được trong tiêu chuẩn này.
Sự không tương thích tiềm ẩn giữa C ++ 14 và C ++ 17 được thảo luận trong C.4. Vì tất cả các tệp tiêu đề không chuẩn được viết bằng C ++ 11 (như được chỉ định trong câu hỏi), những vấn đề này sẽ không xảy ra, vì vậy tôi sẽ không đề cập đến chúng ở đây.
Bây giờ tôi sẽ thảo luận về khả năng tương thích ở cấp trình liên kết. Nói chung, các lý do tiềm ẩn cho sự không tương thích bao gồm:
Nếu định dạng của tệp đối tượng kết quả phụ thuộc vào tiêu chuẩn C ++ đích, trình liên kết phải có khả năng liên kết các tệp đối tượng khác nhau. Trong GCC, LLVM và VC ++, điều này may mắn không xảy ra. Có nghĩa là, định dạng của các tệp đối tượng là giống nhau bất kể tiêu chuẩn đích, mặc dù nó phụ thuộc nhiều vào chính trình biên dịch. Trên thực tế, không có trình liên kết nào của GCC, LLVM và VC ++ yêu cầu kiến thức về tiêu chuẩn C ++ đích. Điều này cũng có nghĩa là chúng ta có thể liên kết các tệp đối tượng đã được biên dịch (liên kết tĩnh trong thời gian chạy).
Nếu quy trình khởi động chương trình (hàm gọi main
) khác nhau đối với các tiêu chuẩn C ++ khác nhau và các quy trình khác nhau không tương thích với nhau, thì sẽ không thể liên kết các tệp đối tượng. Trong GCC, LLVM và VC ++, điều này may mắn không xảy ra. Ngoài ra, chữ ký của main
hàm (và các hạn chế áp dụng cho nó, xem Phần 3.6 của tiêu chuẩn) là giống nhau trong tất cả các tiêu chuẩn C ++, vì vậy nó tồn tại ở đơn vị dịch nào không quan trọng.
Nói chung, WPO có thể không hoạt động tốt với các tệp đối tượng được biên dịch bằng các tiêu chuẩn C ++ khác nhau. Điều này phụ thuộc vào chính xác giai đoạn nào của trình biên dịch yêu cầu kiến thức về tiêu chuẩn mục tiêu và giai đoạn nào không và tác động của nó đối với việc tối ưu hóa liên thủ tục qua các tệp đối tượng. May mắn thay, GCC, LLVM và VC ++ được thiết kế tốt và không có vấn đề này (không phải tôi biết).
Do đó, GCC, LLVM và VC ++ đã được thiết kế để cho phép khả năng tương thích nhị phân trên các phiên bản khác nhau của tiêu chuẩn C ++. Tuy nhiên, đây không thực sự là một yêu cầu của tiêu chuẩn.
Nhân tiện, mặc dù trình biên dịch VC ++ cung cấp công tắc std , cho phép bạn nhắm mục tiêu một phiên bản cụ thể của tiêu chuẩn C ++, nhưng nó không hỗ trợ nhắm mục tiêu C ++ 11. Phiên bản tối thiểu có thể được chỉ định là C ++ 14, là phiên bản mặc định bắt đầu từ Visual C ++ 2013 Update 3. Bạn có thể sử dụng phiên bản VC ++ cũ hơn để nhắm mục tiêu C ++ 11, nhưng sau đó bạn sẽ phải sử dụng các trình biên dịch VC ++ khác nhau để biên dịch các đơn vị dịch khác nhau nhắm mục tiêu các phiên bản khác nhau của tiêu chuẩn C ++, điều này ít nhất sẽ phá vỡ WPO.
CAVEAT: Câu trả lời của tôi có thể không đầy đủ hoặc rất chính xác.