Keywords: C++ Compiler | Standard Version Detection | Cross-Platform Development
Abstract: This article provides an in-depth exploration of technical methods for identifying the C++ language standard version used by compilers in cross-platform development. By analyzing the varying support for the __cplusplus macro across mainstream compilers, combined with compiler-specific macro detection and conditional compilation techniques, practical solutions are presented. The paper details feature detection mechanisms for GCC, MSVC, and other compilers, demonstrating how to accurately identify different standard versions including C++98, C++11, C++14, C++17, and C++20 through macro definition combinations.
Challenges in Compiler Standard Version Detection
In cross-platform C++ development, accurately identifying the language standard version used by the compiler is a common yet complex problem. Although the C++ standard defines the __cplusplus macro to indicate the language version, different compilers exhibit significant variations in their implementation of this macro, creating challenges for writing portable code.
Limitations of Standard Macros
According to C++ standard specifications, the __cplusplus macro should return a long integer value representing the C++ standard version implemented by the compiler:
#include <iostream>
int main() {
std::cout << "C++ Standard Version: " << __cplusplus << std::endl;
return 0;
}
Theoretically, the macro values correspond to different C++ standards: 199711L for C++98, 201103L for C++11, 201402L for C++14, 201703L for C++17, and 202002L for C++20. However, in practical applications, many compilers do not correctly implement this feature.
Compiler-Specific Solutions
Due to the limitations of standard approaches, cross-platform libraries and applications typically employ compiler-specific detection methods. This approach relies on specific macros defined by different compilers to identify the compilation environment and language support.
Microsoft Visual C++ Detection
For MSVC compilers, accurate detection requires combining multiple macros:
#if defined(_MSC_VER) && defined(_MSVC_LANG)
#if _MSVC_LANG >= 202002L
// C++20 features available
#elif _MSVC_LANG >= 201703L
// C++17 features available
#elif _MSVC_LANG >= 201402L
// C++14 features available
#elif _MSVC_LANG >= 201103L
// C++11 features available
#else
// C++98 or earlier versions
#endif
#endif
GCC Compiler Detection
GCC compilers provide version macros and feature detection macros:
#if defined(__GNUC__) && !defined(__clang__)
#if __GNUC__ >= 11
// GCC 11+ supports C++20 features
#elif __GNUC__ >= 7
// GCC 7-10 supports C++17 features
#elif __GNUC__ >= 5
// GCC 5-6 supports C++14 features
#elif __GNUC__ >= 4 && __GNUC_MINOR__ >= 8
// GCC 4.8+ supports C++11 features
#endif
#endif
Comprehensive Detection Framework
In real-world projects, it's often necessary to build a comprehensive detection framework that covers all target compilers:
#ifndef CXX_STANDARD_DETECTED
#define CXX_STANDARD_DETECTED
#if defined(_MSVC_LANG)
#define CXX_STD _MSVC_LANG
#elif defined(__cplusplus)
#define CXX_STD __cplusplus
#else
#define CXX_STD 0L
#endif
// C++ standard version detection
#if CXX_STD >= 202002L
#define CXX_STANDARD 20
#elif CXX_STD >= 201703L
#define CXX_STANDARD 17
#elif CXX_STD >= 201402L
#define CXX_STANDARD 14
#elif CXX_STD >= 201103L
#define CXX_STANDARD 11
#elif CXX_STD >= 199711L
#define CXX_STANDARD 98
#else
#define CXX_STANDARD 0
#endif
#endif // CXX_STANDARD_DETECTED
Compiler Feature Detection
Beyond version detection, a more granular approach involves detecting specific language feature support:
// Detect C++11 features
#if __has_include(<memory>)
#include <memory>
#if defined(__cpp_lib_make_unique) || (__cplusplus >= 201402L)
#define HAS_MAKE_UNIQUE 1
#endif
#endif
// Detect C++17 features
#if defined(__cpp_structured_bindings) || (__cplusplus >= 201703L)
#define HAS_STRUCTURED_BINDINGS 1
#endif
// Detect C++20 features
#if defined(__cpp_concepts) || (__cplusplus >= 202002L)
#define HAS_CONCEPTS 1
#endif
Build System Integration
In large projects, standard version detection is typically integrated into the build system. CMake provides specialized functionality for handling C++ standard detection:
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# Set C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Detect compiler features
target_compile_features(MyTarget PRIVATE cxx_std_17)
# Add compiler-specific flags
if(MSVC)
target_compile_options(MyTarget PRIVATE "/Zc:__cplusplus")
endif()
Best Practice Recommendations
Based on practical development experience, the following best practices are recommended:
- Clearly define target C++ standard versions early in the project and enforce them in the build system
- Use feature detection rather than version detection to ensure code portability
- Maintain specific configurations and macro definitions for different compilers
- Regularly update compiler version detection logic to keep pace with new releases
- Provide clear compile-time error messages in cross-platform libraries to guide users in proper configuration
By comprehensively applying these techniques, developers can build robust cross-platform C++ applications that correctly identify and utilize available language features across different compilation environments.