Làm cách nào để kiểm tra hỗ trợ C ++ 11?


104

Có cách nào để phát hiện tại thời điểm biên dịch nếu trình biên dịch hỗ trợ các tính năng nhất định của C ++ 11 không? Ví dụ, một cái gì đó như thế này:

#ifndef VARIADIC_TEMPLATES_SUPPORTED

#error "Your compiler doesn't support variadic templates.  :("

#else

template <typename... DatatypeList>
class Tuple
{
    // ...
}

#endif

2
Bạn có thể có một tiêu đề được gọi là "khẳng định_variadic_template_support.hpp" mà bạn có thể bao gồm và bên trong làm một cái gì đó giống như template <typename... Test> struct compiler_must_support_variadic_templates;. Một lỗi cú pháp sẽ nhanh chóng tiết lộ vấn đề. (Chỉ là một bên, một thông báo lỗi thích hợp sẽ tốt hơn nhiều.)
GManNickG

Cách 'đúng đắn' để giải quyết vấn đề này là kiểm tra cấu hình.
Joseph Garvin

Câu trả lời:


125

Có một hằng số được đặt tên __cplusplusmà trình biên dịch C ++ nên đặt thành phiên bản của tiêu chuẩn C ++ được hỗ trợ, hãy xem điều này

#if __cplusplus <= 199711L
  #error This library needs at least a C++11 compliant compiler
#endif

Nó được đặt thành 199711L trong Visual Studio 2010 SP1, nhưng tôi không biết liệu các nhà cung cấp có mạnh dạn tăng nó lên hay không nếu họ chỉ hỗ trợ (một phần) mức trình biên dịch so với thư viện C ++ tiêu chuẩn với tất cả các thay đổi C ++ 11 .

Vì vậy, các định nghĩa của Boost được đề cập trong một câu trả lời khác vẫn là cách lành mạnh duy nhất để tìm ra, ví dụ: có hỗ trợ cho các luồng C ++ 11 và các phần cụ thể khác của tiêu chuẩn hay không.


37
C ++ 11 bộ giá trị của __cplusplusđể 201103L. Điều đó khẳng định sự phù hợp hoàn toàn với tiêu chuẩn 2011; nó không cho bạn biết về sự tuân thủ từng phần hoặc phần mở rộng trình biên dịch. Nếu __cplusplusđược đặt thành 201103L, thì hoặc trình biên dịch hoàn toàn phù hợp hoặc nó đang nói dối bạn. Nếu không, thì bạn không thể biết nó hỗ trợ những tính năng nào.
Keith Thompson

1
g ++ 4.7.x (và có lẽ là mới hơn) đặt điều này khi -std=c++11tùy chọn được chỉ định (cũng có thể với -std=gnu++11). Họ làm được điều này, ngay cả khi chúng chưa hoàn chỉnh về tính năng (4.8 đưa chúng ta đến gần hơn). Lưu ý - có một khoảng cách giữa những gì trình biên dịch hỗ trợ và những gì có sẵn trong thư viện chuẩn. Cả 4.7.x & 4.8.x hiện đang thiếu hỗ trợ regex - nhưng đó là một thư viện, không phải là một tính năng biên dịch.
Nathan Ernst

1
Tôi tự hỏi tại sao đây không phải là câu trả lời được chấp nhận. Ngoài ra, bạn có thể sử dụng gợi ý này để cải thiện hơn nữa câu trả lời của mình, nó rất tốt.
Iharob Al Asimi

1
@KeithThompson Đối với tôi, cả Code :: Blocks và Visual Studio thiết lập giá trị của __cplusplusđể 199711Lcho C ++ 11.
Donald Duck

3
@DonaldDuck: Nói chính xác, không, họ không. Một trình biên dịch đặt__cplusplus thành 199711Lkhông phải là trình biên dịch C ++ 11 phù hợp. Họ có thể có các tùy chọn để làm cho họ cư xử đúng.
Keith Thompson

39

Như đã nêu trong tiêu chuẩn C ++ 11 (§iso.16.8):

Tên __cplusplus được xác định giá trị 201103L khi biên dịch đơn vị dịch C ++.

Với giá trị của macro đó, bạn có thể kiểm tra xem trình biên dịch có tuân thủ C ++ 11 hay không.

Bây giờ, nếu bạn đang tìm kiếm một cách tiêu chuẩn để kiểm tra xem trình biên dịch có hỗ trợ một tập hợp con nào của các tính năng C ++ 11 hay không, tôi nghĩ rằng không có cách nào tiêu chuẩn, di động; bạn có thể kiểm tra tài liệu trình biên dịch hoặc tệp tiêu đề thư viện std để có thêm thông tin.


2
Ví dụ: static_assert được hỗ trợ trong VS2010 và trong tất cả các trình biên dịch c ++ 11. Vì vậy, nếu bạn kiểm tra giá trị __cplusplus lớn hơn hoặc bằng giá trị được đặt trong VS2010 (tức là> = 199711L), bạn có thể ổn.
Paolo M

33

Tôi biết rằng đây là một câu hỏi rất cũ, nhưng câu hỏi này có thể bạn thường thấy, và các câu trả lời hơi lỗi thời.

Các trình biên dịch mới hơn với tiêu chuẩn C ++ 14 có một cách tiêu chuẩn để kiểm tra các tính năng, bao gồm cả các tính năng C ++ 11. Trang toàn diện có tại https://isocpp.org/std/ Standing-documents/sd-6-sg10-feature-test-recommendations

Tóm lại, mỗi tính năng có một macro tiêu chuẩn được xác định mà bạn có thể kiểm tra #ifdef. Ví dụ: để kiểm tra các ký tự do người dùng xác định, bạn có thể sử dụng

#ifdef __cpp_user_defined_literals

1
Tôi không biết điều đó. Tôi nghĩ rằng tính năng đơn giản này đến muộn, nhưng vẫn có thể rất hữu ích, đặc biệt là __has_include()macro.
prapin vào

22

Để kiểm tra hỗ trợ C ++ 14 và khác. Thử nghiệm trên GCC 5.2.1.

#include <iostream>

int main(){
        #if __cplusplus==201402L
        std::cout << "C++14" << std::endl;
        #elif __cplusplus==201103L
        std::cout << "C++11" << std::endl;
        #else
        std::cout << "C++" << std::endl;
        #endif

        return 0;
}

17

Bạn có thể sử dụng cái này:

#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
    cout << "C++11 is supported";
#else
    cout << "C++11 is not supported";
#endif

Đối với C ++ 11, hầu hết các trình biên dịch ngoại trừ Visual Studio đều đặt __cplusplusmacro tại 201103L, nhưng bất kỳ phiên bản nào của Visual Studio đều đặt macro tại 199711Lđó là giá trị được sử dụng cho các trình biên dịch khác trước C ++ 11. Mã này so sánh _cplusplusmacro với 201103Ltất cả các trình biên dịch ngoại trừ Visual Studio và nếu trình biên dịch là Visual Studio, nó sẽ kiểm tra xem phiên bản Visual Studio có mới hơn năm 2015 hay không, phiên bản đầu tiên của Visual Studio hỗ trợ hoàn toàn C ++ 11 (dành cho Visual Studio 2015, _MSC_VERmacro có giá trị 1900, hãy xem câu trả lời này ).


1
Câu trả lời này không chính xác. Đối g++ -std=c++98với GCC 4.8, nó in không chính xác C++11 is supported.
pts

1
@pts Xin lỗi, chỉ là lỗi đánh máy. Nó nên được chữa ngay bây giờ.
Vịt Donald

7

Nếu bạn không muốn sử dụng Boost.Config và cần kiểm tra trình biên dịch hỗ trợ C ++ 11 thì việc kiểm tra giá trị của hằng số __cplusplussẽ được thực hiện. Tuy nhiên, một trình biên dịch có thể hỗ trợ hầu hết các tính năng phổ biến của tiêu chuẩn C ++ 11 nhưng nó không hỗ trợ toàn bộ thông số kỹ thuật. Nếu bạn muốn bật hỗ trợ cho các trình biên dịch Visual Studio cụ thể chưa tuân thủ 100% thông số kỹ thuật C ++ 11 thì hãy sử dụng đoạn mã sau cho phép biên dịch trong Visual Studio 2013:

#if defined(_MSC_VER)
#   if _MSC_VER < 1800 
#       error This project needs atleast Visual Studio 2013
#   endif
#elif __cplusplus <= 199711L
#   error This project can only be compiled with a compiler that supports C++11
#endif

Danh sách đầy đủ các phiên bản của trình biên dịch cho Visual Studio được cung cấp tại Cách phát hiện nếu tôi đang biên dịch mã bằng Visual Studio 2008


6

Trong thế giới Linux / Unix truyền thống, autoconf theo truyền thống được sử dụng để kiểm tra sự hiện diện của các thư viện và các tính năng của trình biên dịch cũng như các lỗi đặt chúng vào config.h mà bạn sử dụng trong các tệp của mình khi cần.


2
Có autoconf có thể được sử dụng để kiểm tra các tính năng nhưng bạn phải làm cho nó tạo macro thích hợp cho sự thất bại hoặc thành công mà sau đó có thể được kiểm tra bằng đoạn mã trên. Vì vậy, tự nó câu trả lời này không thêm thông tin.
Martin York

3
@LokiAstari: Đó không phải là cách autoconf hoạt động. Autoconf cung cấp các macro cho phép bạn cấu hình tập lệnh biên dịch tệp nguồn thử nghiệm và đặt #define thành 0 hoặc 1 dựa trên sự thành công của quá trình biên dịch. Câu trả lời củaverscuba23 cung cấp thông tin bằng cách chỉ ra OP đang đạt được giải pháp tối ưu cho vấn đề thực sự.
Joseph Garvin


1

Khi bạn kiểm tra tính khả dụng của thư viện C ++ 11 (không phải tính năng ngôn ngữ), chẳng hạn như <array>tiêu đề, bạn có thể #if __has_include(<array>).

Đôi khi việc kiểm tra #if __cplusplus >= 201103Lsẽ cho bạn biết rằng bạn sử dụng C ++ 11 nhưng các cài đặt khác như cài đặt phiên bản thư viện tiêu chuẩn trong Xcode có thể vẫn không có sẵn các thư viện mới (hầu hết chúng đều có sẵn với các tên khác nhau <tr1/array>)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.