ฉันจะตรวจสอบการรองรับ C ++ 11 ได้อย่างไร


104

มีวิธีตรวจจับในเวลาคอมไพล์หรือไม่ว่าคอมไพเลอร์รองรับคุณสมบัติบางอย่างของ C ++ 11 หรือไม่? ตัวอย่างเช่นสิ่งนี้:

#ifndef VARIADIC_TEMPLATES_SUPPORTED

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

#else

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

#endif

2
คุณสามารถมีส่วนหัวที่เรียกว่า "assert_variadic_template_support.hpp" ซึ่งคุณสามารถรวมไว้และทำสิ่งที่ต้องการtemplate <typename... Test> struct compiler_must_support_variadic_templates;ได้ ข้อผิดพลาดทางไวยากรณ์จะเปิดเผยปัญหาอย่างรวดเร็ว (นอกจากข้อความแสดงข้อผิดพลาดที่เหมาะสมจะดีกว่ามาก)
GManNickG

วิธีที่ 'ถูกต้อง' ในการแก้ปัญหานี้คือกำหนดค่าการทดสอบ
Joseph Garvin

คำตอบ:


125

มีชื่อค่าคง__cplusplusที่ที่คอมไพเลอร์ C ++ ควรตั้งค่าเป็นเวอร์ชันของมาตรฐาน C ++ ที่รองรับดูสิ่งนี้

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

ตั้งค่าเป็น 199711L ใน Visual Studio 2010 SP1 แต่ฉันไม่รู้ว่าผู้ขายจะกล้าเพิ่มขนาดนี้หรือไม่หากพวกเขามีการสนับสนุนระดับคอมไพเลอร์ (บางส่วน) เทียบกับไลบรารี C ++ มาตรฐานที่มีการเปลี่ยนแปลง C ++ 11 ทั้งหมด .

ดังนั้นคำจำกัดความของ Boost ที่กล่าวถึงในคำตอบอื่นยังคงเป็นวิธีเดียวที่ดีในการพิจารณาว่ามีการสนับสนุนเธรด C ++ 11 และส่วนอื่น ๆ ของมาตรฐานหรือไม่


37
C ++ 11 ชุดค่าของการ__cplusplus 201103Lนั่นแสดงถึงการปฏิบัติตามมาตรฐาน 2011 อย่างสมบูรณ์ ไม่ได้บอกคุณเกี่ยวกับความสอดคล้องบางส่วนหรือส่วนขยายของคอมไพเลอร์ หาก__cplusplusตั้งค่า201103Lเป็นคอมไพลเลอร์จะสอดคล้องอย่างสมบูรณ์หรือกำลังโกหกคุณ ถ้าไม่เป็นเช่นนั้นคุณจะไม่สามารถบอกได้ว่าฟีเจอร์ใดรองรับ
Keith Thompson

1
g ++ 4.7.x (และน่าจะใหม่กว่า) ตั้งค่านี้เมื่อ-std=c++11ระบุตัวเลือก (อาจมีด้วย-std=gnu++11) พวกเขาทำเช่นนี้แม้ว่าฟีเจอร์จะยังไม่สมบูรณ์ก็ตาม (4.8 ทำให้เราใกล้ชิดมากขึ้น) หมายเหตุ - มีช่องว่างระหว่างสิ่งที่คอมไพเลอร์สนับสนุนและสิ่งที่มีอยู่ในไลบรารีมาตรฐาน ขณะนี้ทั้ง 4.7.x และ 4.8.x ไม่มีการรองรับ regex แต่นั่นคือไลบรารีไม่ใช่ฟีเจอร์คอมไพเลอร์
Nathan Ernst

1
ฉันสงสัยว่าเหตุใดจึงไม่เป็นคำตอบที่ยอมรับ นอกจากนี้คุณสามารถใช้คำแนะนำนี้เพื่อปรับปรุงคำตอบของคุณได้ดีมาก
Iharob Al Asimi

1
@KeithThompson สำหรับฉันทั้ง Code :: Blocks และ Visual Studio ตั้งค่า__cplusplusเป็น199711Lสำหรับ C ++ 11
Donald Duck

3
@DonaldDuck: พูดอย่างเคร่งครัดไม่พวกเขาไม่ทำ เรียบเรียงว่าชุด__cplusplusจะ199711Lไม่ได้เป็นไปตามกลไก C ++ 11 คอมไพเลอร์ พวกเขาอาจมีทางเลือกที่จะทำให้พวกเขาปฏิบัติอย่างถูกต้อง
Keith Thompson

39

ตามที่ระบุไว้ในมาตรฐานC ++ 11 (§iso.16.8):

ชื่อ__cplusplusถูกกำหนดให้เป็นค่า201103Lเมื่อรวบรวมหน่วยการแปล C ++

ด้วยค่าของแมโครดังกล่าวคุณสามารถตรวจสอบว่าคอมไพเลอร์เป็นไปตาม C ++ 11 หรือไม่

ตอนนี้หากคุณกำลังมองหาวิธีมาตรฐานในการตรวจสอบว่าคอมไพเลอร์รองรับชุดย่อยของคุณสมบัติ C ++ 11 หรือไม่ฉันคิดว่าไม่มีวิธีมาตรฐานแบบพกพา คุณสามารถตรวจสอบเอกสารประกอบคอมไพเลอร์หรือไฟล์ส่วนหัวไลบรารี std เพื่อรับข้อมูลเพิ่มเติม


2
ตัวอย่างเช่น static_assert ได้รับการสนับสนุนใน VS2010 และในตัวคัดลอก c ++ 11 ทั้งหมด ดังนั้นหากคุณตรวจสอบค่า __cplusplus ที่มากกว่าหรือเท่ากับที่กำหนดใน VS2010 (เช่น> = 199711L) คุณก็สบายดี
Paolo M

33

ฉันรู้ว่านี่เป็นคำถามที่เก่ามาก แต่อาจมีคนเห็นคำถามนี้อยู่บ่อยครั้งและคำตอบค่อนข้างล้าสมัย

คอมไพเลอร์รุ่นใหม่ที่มีมาตรฐาน C ++ 14 มีวิธีมาตรฐานในการตรวจสอบคุณสมบัติรวมถึงคุณสมบัติ C ++ 11 เพจที่ครอบคลุมอยู่ที่https://isocpp.org/std/stand-documents/sd-6-sg10-feature-test-recommendations

โดยสรุปแล้วแต่ละคุณลักษณะจะมีมาโครมาตรฐานที่กำหนดไว้ซึ่งคุณสามารถตรวจสอบ#ifdefได้ ตัวอย่างเช่นในการตรวจสอบตัวอักษรที่ผู้ใช้กำหนดคุณสามารถใช้

#ifdef __cpp_user_defined_literals

1
ฉันไม่รู้เรื่องนั้น ฉันคิดว่าฟีเจอร์ง่ายๆนี้มาช้า แต่ก็ยังมีประโยชน์มากโดยเฉพาะ__has_include()มาโคร
prapin

22

สำหรับตรวจสอบการสนับสนุน C ++ 14 และอื่น ๆ การทดสอบ 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

คุณสามารถใช้สิ่งนี้:

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

สำหรับ C ++ 11 คอมไพเลอร์ส่วนใหญ่ยกเว้น Visual Studio จะตั้งค่า__cplusplusมาโครที่201103Lแต่ Visual Studio เวอร์ชันใดก็ได้ตั้งค่า199711Lซึ่งเป็นค่าที่ใช้สำหรับคอมไพเลอร์อื่นก่อน C ++ 11 โค้ดนี้จะเปรียบเทียบ_cplusplusมาโครกับ201103Lคอมไพเลอร์ทั้งหมดยกเว้น Visual Studio และถ้าคอมไพเลอร์เป็น Visual Studio จะตรวจสอบว่า Visual Studio เวอร์ชันใหม่กว่า 2015 ซึ่งเป็นเวอร์ชันแรกของ Visual Studio ซึ่งรองรับ C ++ 11 อย่างสมบูรณ์ (สำหรับ Visual Studio 2015 _MSC_VERมาโครมีค่า1900ดูคำตอบนี้ )


1
คำตอบนี้ไม่ถูกต้อง สำหรับg++ -std=c++98กับ GCC 4.8 C++11 is supportedมันไม่ถูกต้องพิมพ์
pts

1
@pts ขออภัยเพียงพิมพ์ผิด ตอนนี้ควรได้รับการแก้ไขแล้ว
Donald Duck

8

หากคุณไม่ต้องการใช้ Boost.Config และต้องการทดสอบคอมไพเลอร์ที่รองรับ C ++ 11 จากนั้นตรวจสอบค่าของค่าคงที่__cplusplusจะทำ อย่างไรก็ตามคอมไพลเลอร์อาจรองรับคุณสมบัติยอดนิยมส่วนใหญ่ของมาตรฐาน C ++ 11 แต่ก็ไม่รองรับข้อกำหนดทั้งหมด หากคุณต้องการเปิดใช้งานการสนับสนุนสำหรับคอมไพเลอร์ Visual Studio เฉพาะซึ่งยังไม่สอดคล้องกับข้อกำหนด C ++ 11 100% ให้ใช้ข้อมูลโค้ดต่อไปนี้ซึ่งอนุญาตให้คอมไพล์ใน 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

รายการเวอร์ชันทั้งหมดของคอมไพเลอร์สำหรับ Visual Studio มีให้ที่How to Detect if I'm Compiling Code With Visual Studio 2008


6

ในโลก Linux / Unix แบบดั้งเดิม autoconf ถูกใช้เพื่อทดสอบการมีอยู่ของไลบรารีและคุณสมบัติคอมไพเลอร์และจุดบกพร่องที่วางไว้ใน config.h ที่คุณใช้ในไฟล์ของคุณตามต้องการ


2
ใช่สามารถใช้ autoconf เพื่อทดสอบคุณสมบัติได้ แต่คุณต้องสร้างมาโครที่เหมาะสมสำหรับความล้มเหลวหรือความสำเร็จที่สามารถทดสอบได้ตามโค้ดด้านบน ดังนั้นคำตอบนี้จึงไม่เพิ่มข้อมูล
Martin York

3
@LokiAstari: นั่นไม่ใช่วิธีการทำงานของ autoconf Autoconf จัดเตรียมมาโครที่ให้คุณกำหนดค่าสคริปต์ของคุณคอมไพล์ไฟล์ต้นฉบับทดสอบและตั้งค่า #define เป็น 0 หรือ 1 ตามความสำเร็จของการคอมไพล์ คำตอบของ Diverscuba23 ให้ข้อมูลโดยชี้ว่า OP กำลังหาทางแก้ปัญหาที่ไม่เหมาะสมสำหรับปัญหาที่แท้จริง
Joseph Garvin


1

เมื่อการตรวจสอบของคุณใช้สำหรับ C ++ 11 พร้อมใช้งานห้องสมุด (ไม่ใช่คุณลักษณะภาษา) สำหรับตัวอย่างส่วนหัวของคุณสามารถ<array>#if __has_include(<array>)

บางครั้งการตรวจสอบ#if __cplusplus >= 201103Lจะบอกคุณว่าคุณใช้ C ++ 11 แต่การตั้งค่าอื่น ๆ เช่นการตั้งค่าเวอร์ชันไลบรารีมาตรฐานใน Xcode อาจยังไม่มีไลบรารีใหม่ที่พร้อมใช้งาน (ส่วนใหญ่มีอยู่ในชื่ออื่นเช่น<tr1/array>)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.