Bagaimana cara memeriksa dukungan C ++ 11?

104

Apakah ada cara untuk mendeteksi pada waktu kompilasi jika kompilator mendukung fitur tertentu C ++ 11? Misalnya, seperti ini:

#ifndef VARIADIC_TEMPLATES_SUPPORTED

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

#else

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

#endif
Maxpm
sumber
2
Anda dapat memiliki sebuah header bernama "assert_variadic_template_support.hpp" yang dapat Anda sertakan dan dalam melakukan sesuatu seperti template <typename... Test> struct compiler_must_support_variadic_templates;. Kesalahan sintaksis akan segera mengungkap masalahnya. (Selain itu, pesan kesalahan yang tepat jauh lebih baik.)
GManNickG
Cara yang 'tepat' untuk mengatasi masalah ini adalah tes konfigurasi.
Joseph Garvin

Jawaban:

125

Ada konstanta bernama __cplusplusyang harus disetel oleh compiler C ++ ke versi standar C ++ yang didukung. Lihat ini

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

Ini diatur ke 199711L dalam Visual Studio 2010 SP1, tetapi saya tidak tahu apakah vendor akan begitu berani untuk meningkatkannya jika mereka hanya memiliki (sebagian) dukungan tingkat kompiler versus pustaka C ++ standar dengan semua perubahan C ++ 11 .

Jadi definisi Boost yang disebutkan dalam jawaban lain tetap menjadi satu-satunya cara yang masuk akal untuk mengetahui apakah ada, misalnya, dukungan untuk utas C ++ 11 dan bagian spesifik lainnya dari standar.

Cygon
sumber
37
C ++ 11 menetapkan nilai __cplusplusmenjadi 201103L. Itu menegaskan kesesuaian penuh dengan standar 2011; itu tidak memberi tahu Anda tentang kesesuaian parsial atau ekstensi kompilator. Jika __cplusplusdisetel ke 201103L, maka kompilator sepenuhnya sesuai atau berbohong kepada Anda. Jika tidak, maka Anda tidak dapat benar-benar mengetahui fitur mana yang didukungnya.
Keith Thompson
1
g ++ 4.7.x (dan mungkin lebih baru) menyetel ini saat -std=c++11opsi ditentukan (mungkin juga dengan -std=gnu++11). Mereka melakukan ini, meskipun fitur mereka belum cukup lengkap (4.8 membawa kita lebih dekat). Catatan - ada celah antara apa yang didukung kompilator dan yang tersedia di pustaka standar. Baik 4.7.x & 4.8.x saat ini tidak memiliki dukungan regex - tetapi itu adalah pustaka, bukan fitur kompiler.
Nathan Ernst
1
Saya bertanya-tanya mengapa ini bukan jawaban yang diterima. Juga, Anda dapat menggunakan saran ini untuk lebih meningkatkan jawaban Anda, ini sangat bagus.
Iharob Al Asimi
1
@KeithThompson Bagi saya, baik Code :: Blocks dan Visual Studio menetapkan nilai __cplusplusmenjadi 199711Luntuk C ++ 11.
Donald Duck
3
@DonaldDuck: Sebenarnya, tidak, mereka tidak. Sebuah compiler yang set __cplusplusuntuk 199711Ltidak sesuai C ++ 11 compiler. Mereka mungkin memiliki opsi untuk membuat mereka berperilaku dengan benar.
Keith Thompson
39

Seperti yang dinyatakan oleh standar C ++ 11 (§iso.16.8):

Nama __cplusplus didefinisikan ke nilai 201103L saat menyusun unit terjemahan C ++.

Dengan nilai makro itu, Anda dapat memeriksa apakah kompilernya sesuai dengan C ++ 11.

Sekarang, jika Anda mencari cara standar untuk memeriksa apakah kompiler mendukung subset fitur C ++ 11, saya rasa tidak ada cara standar dan portabel; Anda dapat memeriksa dokumentasi kompiler atau file header perpustakaan std untuk mendapatkan informasi lebih lanjut.

Paolo M
sumber
2
Misalnya, static_assert didukung di VS2010 dan di semua kopiler c ++ 11. Jadi, jika Anda memeriksa nilai __cplusplus lebih besar atau sama dari yang ditetapkan di VS2010 (yaitu> = 199711L), Anda bisa baik-baik saja.
Paolo M
33

Saya tahu bahwa ini adalah pertanyaan yang sangat lama, tetapi pertanyaan ini mungkin sering terlihat, dan jawabannya agak ketinggalan zaman.

Compiler baru dengan standar C ++ 14 memiliki cara standar untuk memeriksa fitur, termasuk fitur C ++ 11. Halaman lengkapnya ada di https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations

Singkatnya, setiap fitur memiliki makro standar yang ditentukan yang dapat Anda periksa #ifdef . Misalnya, untuk memeriksa literal yang ditentukan pengguna, Anda dapat menggunakan

#ifdef __cpp_user_defined_literals
Jarryd
sumber
1
Saya tidak tahu itu. Saya pikir fitur sederhana ini akan datang terlambat, tetapi masih bisa sangat berguna, terutama __has_include()makro.
prapin
22

Untuk memeriksa dukungan C ++ 14 dan lainnya. Pengujian di 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;
}
kurono267
sumber
17

Anda dapat menggunakan ini:

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

Untuk C ++ 11, sebagian besar kompiler kecuali Visual Studio menetapkan __cplusplusmakro 201103L, tetapi versi Visual Studio mana pun menetapkannya di 199711Lmana nilai yang digunakan untuk kompiler lain sebelum C ++ 11. Kode ini membandingkan _cplusplusmakro dengan 201103Luntuk semua kompiler kecuali Visual Studio, dan jika kompilernya adalah Visual Studio, ia memeriksa apakah versi Visual Studio lebih lambat dari 2015, versi pertama Visual Studio yang sepenuhnya mendukung C ++ 11 (untuk Visual Studio 2015, _MSC_VERmakro memiliki nilai 1900, lihat jawaban ini ).

Donald Bebek
sumber
1
Jawaban ini salah. Karena g++ -std=c++98dengan GCC 4.8, pencetakannya salah C++11 is supported.
poin
1
@pts Maaf, salah ketik. Seharusnya sudah diperbaiki sekarang.
Donald Duck
7

Jika Anda tidak ingin menggunakan Boost.Config dan perlu menguji kompiler yang mendukung C ++ 11, maka memeriksa nilai konstanta __cplusplusakan dilakukan. Namun, kompiler mungkin mendukung sebagian besar fitur populer dari standar C ++ 11 namun tidak mendukung seluruh spesifikasi. Jika Anda ingin mengaktifkan dukungan untuk kompiler Visual Studio tertentu yang belum 100% sesuai dengan spesifikasi C ++ 11, gunakan potongan kode berikut yang memungkinkan kompilasi di 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

Daftar lengkap versi kompiler untuk Visual Studio tersedia di cara mendeteksi jika saya sedang menyusun kode dengan Visual Studio 2008

Vamshi Krishna
sumber
6

Di dunia Linux / Unix tradisional, autoconf secara tradisional digunakan untuk menguji keberadaan pustaka dan fitur kompilator dan bug menempatkannya ke dalam config.h yang Anda gunakan di file sesuai kebutuhan.

diverscuba23
sumber
2
Ya, autoconf dapat digunakan untuk menguji fitur tetapi Anda harus membuatnya menghasilkan makro yang sesuai untuk kegagalan atau keberhasilan yang kemudian dapat diuji oleh kode di atas. Jadi dengan sendirinya jawaban ini tidak menambah informasi.
Martin York
3
@LokiAstari: Itu bukan cara kerja autoconf. Autoconf menyediakan makro yang memungkinkan Anda membuat skrip konfigurasi mengompilasi file sumber pengujian dan menyetel #define ke 0 atau 1 berdasarkan keberhasilan kompilasi. Jawaban diverscuba23 memberikan informasi dengan menunjukkan OP sedang mencapai solusi suboptimal untuk masalah sebenarnya.
Joseph Garvin
1

Jika pemeriksaan Anda adalah untuk ketersediaan pustaka C ++ 11 (bukan fitur bahasa), misalnya <array>header, Anda bisa #if __has_include(<array>).

Terkadang pemeriksaan #if __cplusplus >= 201103Lakan memberi tahu Anda bahwa Anda menggunakan C ++ 11 tetapi pengaturan lain seperti pengaturan versi perpustakaan standar di Xcode mungkin masih tidak memiliki perpustakaan baru yang tersedia (kebanyakan dari mereka tersedia dalam nama yang berbeda yaitu <tr1/array>)

yairchu
sumber