How are the __cplusplus directive defined in various compilers?

Learn how are the __cplusplus directive defined in various compilers? with practical examples, diagrams, and best practices. Covers c++, preprocessor-directive, compiler-version development techniq...

Understanding the __cplusplus Directive Across C++ Compilers

A stylized C++ logo with a preprocessor directive symbol overlayed, representing compiler version detection.

Explore how the __cplusplus preprocessor directive is defined by various C++ compilers, its historical evolution, and how to use it for conditional compilation based on C++ standard versions.

The __cplusplus preprocessor directive is a fundamental tool for C++ developers, allowing code to adapt to different C++ language standards. This macro is automatically defined by C++ compilers and expands to a long integer literal that indicates the version of the C++ standard being used. Understanding its values across various compilers and standards is crucial for writing portable and future-proof C++ code.

The Purpose of __cplusplus

The primary purpose of __cplusplus is to enable conditional compilation. Developers can use #if or #ifdef directives to include or exclude specific blocks of code based on the C++ standard supported by the compiler. This is particularly useful when leveraging new language features, deprecating old ones, or providing compatibility layers for different C++ versions. For instance, you might want to use C++11's std::thread if available, but fall back to platform-specific threading APIs on older compilers.

#include <iostream>

int main() {
    std::cout << "__cplusplus value: " << __cplusplus << std::endl;

    #if __cplusplus >= 201103L
        std::cout << "C++11 or later detected." << std::endl;
    #elif __cplusplus >= 199711L
        std::cout << "C++98/03 detected." << std::endl;
    #else
        std::cout << "Older C++ standard or non-standard compiler." << std::endl;
    #endif

    return 0;
}

Basic usage of __cplusplus for version detection

Historical Evolution of __cplusplus Values

The value of __cplusplus has evolved with each new C++ standard. Initially, it was simply 1 for C++98. However, with the introduction of C++11, a more structured approach was adopted, using a YYYYMM format (or YYYYMMLL for C++11 and later) to represent the standard's publication date. This allows for more granular detection of standard versions.

A bar chart showing the __cplusplus values for different C++ standards: C++98/03 (199711L), C++11 (201103L), C++14 (201402L), C++17 (201703L), C++20 (202002L), and C++23 (202302L). Each bar is labeled with the standard and its corresponding value.

Standard __cplusplus values over time

Compiler-Specific Behaviors and Flags

While the C++ standard specifies the values for __cplusplus, some compilers historically deviated or required specific flags to enable the correct value. For example, older versions of GCC and Clang might require the -std=c++11 or -std=c++14 flag to define __cplusplus correctly for those standards. Microsoft Visual C++ (MSVC) has its own set of predefined macros and historically did not update __cplusplus to the standard-mandated values by default, instead providing _MSVC_LANG for this purpose. However, modern MSVC versions (from Visual Studio 2015 Update 3 onwards) can define __cplusplus correctly when using the /Zc:__cplusplus compiler option.

#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
    // MSVC with C++17 or later
    std::cout << "MSVC C++17 or later detected via _MSVC_LANG." << std::endl;
#elif __cplusplus >= 201703L
    // Other compilers with C++17 or later, or MSVC with /Zc:__cplusplus
    std::cout << "C++17 or later detected via __cplusplus." << std::endl;
#else
    std::cout << "Older C++ standard or different compiler." << std::endl;
#endif

Handling MSVC's _MSVC_LANG alongside __cplusplus

Practical Application: Feature Detection

Beyond simply detecting the C++ standard, __cplusplus is often used in conjunction with other feature-test macros (like __has_include or __cpp_lib_filesystem) to detect the availability of specific language or library features. This allows for highly granular control over code paths, ensuring that your application compiles and runs correctly across a wide range of compiler environments and C++ standard versions.

graph TD
    A[Start]
    B{Compiler supports C++17?}
    C{MSVC with /Zc:__cplusplus?}
    D{Use C++17 features}
    E{MSVC with _MSVC_LANG >= 201703L?}
    F{Use C++17 features (MSVC specific)}
    G{Use C++14 features}
    H[End]

    A --> B
    B -- Yes --> D
    B -- No --> C
    C -- Yes --> D
    C -- No --> E
    E -- Yes --> F
    E -- No --> G
    D --> H
    F --> H
    G --> H

Decision flow for C++17 feature detection across compilers