TRLC Platform Library  1.0.0
Header-only C++ library for compile-time platform detection and abstraction
cpp_standard.hpp
Go to the documentation of this file.
1 
13 #pragma once
14 
15 namespace trlc {
16 namespace platform {
17 
24 enum class CppStandard : long {
25  cpp_pre_17 = 0,
26  cpp_17 = 201703L,
27  cpp_20 = 202002L,
28  cpp_23 = 202302L,
29  cpp_26 = 202600L,
30  cpp_unknown = -1
31 };
32 
42  const char* standard_name;
43 
49  constexpr bool isAtLeast(CppStandard min_standard) const noexcept {
50  return static_cast<long>(standard) >= static_cast<long>(min_standard);
51  }
52 
58  constexpr bool supportsFeature(const char* feature_name) const noexcept {
59  // Note: This is a simplified implementation. In practice, this could
60  // be extended with a more sophisticated feature mapping system.
61 
62  // Compare strings at compile time (simplified for key features)
63  if (feature_name[0] == 's' && feature_name[1] == 't' && feature_name[2] == 'r' &&
64  feature_name[3] == 'u' && feature_name[4] == 'c' && feature_name[5] == 't') {
65  // "structured_bindings"
67  }
68  if (feature_name[0] == 'i' && feature_name[1] == 'f' && feature_name[2] == '_' &&
69  feature_name[3] == 'c' && feature_name[4] == 'o' && feature_name[5] == 'n') {
70  // "if_constexpr"
72  }
73  if (feature_name[0] == 'c' && feature_name[1] == 'o' && feature_name[2] == 'n' &&
74  feature_name[3] == 'c' && feature_name[4] == 'e' && feature_name[5] == 'p') {
75  // "concepts"
77  }
78  if (feature_name[0] == 'c' && feature_name[1] == 'o' && feature_name[2] == 'r' &&
79  feature_name[3] == 'o' && feature_name[4] == 'u' && feature_name[5] == 't') {
80  // "coroutines"
82  }
83  if (feature_name[0] == 'm' && feature_name[1] == 'o' && feature_name[2] == 'd' &&
84  feature_name[3] == 'u' && feature_name[4] == 'l' && feature_name[5] == 'e') {
85  // "modules"
87  }
88  if (feature_name[0] == 'r' && feature_name[1] == 'a' && feature_name[2] == 'n' &&
89  feature_name[3] == 'g' && feature_name[4] == 'e' && feature_name[5] == 's') {
90  // "ranges"
92  }
93 
94  return false; // Unknown feature
95  }
96 };
97 
98 namespace detail {
99 
104 constexpr CppStandard detectCppStandard() noexcept {
105  // Use _MSVC_LANG for MSVC, __cplusplus for others
106 #if defined(_MSVC_LANG)
107  constexpr long cpp_version = _MSVC_LANG;
108 #elif defined(__cplusplus)
109  constexpr long cpp_version = __cplusplus;
110 #else
111  constexpr long cpp_version = 0L;
112 #endif
113 
114  if (cpp_version >= 202600L) {
115  return CppStandard::cpp_26;
116  } else if (cpp_version >= 202302L) {
117  return CppStandard::cpp_23;
118  } else if (cpp_version >= 202002L) {
119  return CppStandard::cpp_20;
120  } else if (cpp_version >= 201703L) {
121  return CppStandard::cpp_17;
122  } else if (cpp_version >= 201402L || cpp_version >= 201103L || cpp_version >= 199711L) {
124  } else {
126  }
127 }
128 
133 constexpr long getCppVersionMacroValue() noexcept {
134 #if defined(_MSVC_LANG)
135  return _MSVC_LANG; // MSVC uses _MSVC_LANG instead of __cplusplus
136 #elif defined(__cplusplus)
137  return __cplusplus;
138 #else
139  return 0L;
140 #endif
141 }
142 
147 constexpr const char* getCppStandardName() noexcept {
148  constexpr auto standard = detectCppStandard();
149  switch (standard) {
150  case CppStandard::cpp_17:
151  return "C++17";
152  case CppStandard::cpp_20:
153  return "C++20";
154  case CppStandard::cpp_23:
155  return "C++23";
156  case CppStandard::cpp_26:
157  return "C++26";
159  return "Pre-C++17";
160  default:
161  return "Unknown";
162  }
163 }
164 
165 } // namespace detail
166 
171 constexpr CppStandard getCppStandard() noexcept {
172  return detail::detectCppStandard();
173 }
174 
179 constexpr CppStandardInfo getCppStandardInfo() noexcept {
183 }
184 
189 constexpr long getCppVersionMacro() noexcept {
191 }
192 
193 // Standard feature detection functions
194 
199 constexpr bool hasStructuredBindings() noexcept {
200 #ifdef __cpp_structured_bindings
201  return __cpp_structured_bindings >= 201606L;
202 #else
204 #endif
205 }
206 
211 constexpr bool hasIfConstexpr() noexcept {
212 #ifdef __cpp_if_constexpr
213  return __cpp_if_constexpr >= 201606L;
214 #else
216 #endif
217 }
218 
223 constexpr bool hasConcepts() noexcept {
224 #ifdef __cpp_concepts
225  return __cpp_concepts >= 201907L;
226 #else
228 #endif
229 }
230 
235 constexpr bool hasCoroutines() noexcept {
236 #ifdef __cpp_impl_coroutine
237  return __cpp_impl_coroutine >= 201902L;
238 #elif defined(__cpp_coroutines)
239  return __cpp_coroutines >= 201902L;
240 #else
242 #endif
243 }
244 
249 constexpr bool hasModules() noexcept {
250 #ifdef __cpp_modules
251  return __cpp_modules >= 201907L;
252 #else
253  // Modules support varies significantly by compiler, be conservative
254  return false;
255 #endif
256 }
257 
262 constexpr bool hasRanges() noexcept {
263 #ifdef __cpp_lib_ranges
264  return __cpp_lib_ranges >= 201911L;
265 #else
267 #endif
268 }
269 
274 constexpr bool hasFoldExpressions() noexcept {
275 #ifdef __cpp_fold_expressions
276  return __cpp_fold_expressions >= 201603L;
277 #else
279 #endif
280 }
281 
286 constexpr bool hasInlineVariables() noexcept {
287 #ifdef __cpp_inline_variables
288  return __cpp_inline_variables >= 201606L;
289 #else
291 #endif
292 }
293 
298 constexpr bool hasConsteval() noexcept {
299 #ifdef __cpp_consteval
300  return __cpp_consteval >= 201811L;
301 #else
303 #endif
304 }
305 
310 constexpr bool hasConstinit() noexcept {
311 #ifdef __cpp_constinit
312  return __cpp_constinit >= 201907L;
313 #else
315 #endif
316 }
317 
322 constexpr bool hasDesignatedInitializers() noexcept {
323 #ifdef __cpp_designated_initializers
324  return __cpp_designated_initializers >= 201707L;
325 #else
327 #endif
328 }
329 
334 constexpr bool hasThreeWayComparison() noexcept {
335 #ifdef __cpp_impl_three_way_comparison
336  return __cpp_impl_three_way_comparison >= 201907L;
337 #else
339 #endif
340 }
341 
346 constexpr bool isCpp17OrLater() noexcept {
348 }
349 
354 constexpr bool isCpp20OrLater() noexcept {
356 }
357 
362 constexpr bool isCpp23OrLater() noexcept {
364 }
365 
370 constexpr bool isExactlyCpp17() noexcept {
372 }
373 
378 constexpr bool isExactlyCpp20() noexcept {
380 }
381 
386 constexpr bool isExactlyCpp23() noexcept {
388 }
389 
390 } // namespace platform
391 } // namespace trlc
392 
393 // Convenience macros for C++ standard detection (preprocessor-compatible)
394 
395 // Standard version macros
396 #if defined(__cplusplus) && __cplusplus >= 201703L
397  #define TRLC_CPP17 1
398 #else
399  #define TRLC_CPP17 0
400 #endif
401 
402 #if defined(__cplusplus) && __cplusplus >= 202002L
403  #define TRLC_CPP20 1
404 #else
405  #define TRLC_CPP20 0
406 #endif
407 
408 #if defined(__cplusplus) && __cplusplus >= 202302L
409  #define TRLC_CPP23 1
410 #else
411  #define TRLC_CPP23 0
412 #endif
413 
414 #if defined(__cplusplus) && __cplusplus >= 202600L
415  #define TRLC_CPP26 1
416 #else
417  #define TRLC_CPP26 0
418 #endif
419 
420 // Version macro value
421 #ifdef __cplusplus
422  #define TRLC_CPP_VERSION __cplusplus
423 #else
424  #define TRLC_CPP_VERSION 0L
425 #endif
426 
427 // Feature detection macros (preprocessor-compatible)
428 #ifdef __cpp_structured_bindings
429  #if __cpp_structured_bindings >= 201606L
430  #define TRLC_HAS_STRUCTURED_BINDINGS 1
431  #else
432  #define TRLC_HAS_STRUCTURED_BINDINGS 0
433  #endif
434 #else
435  #define TRLC_HAS_STRUCTURED_BINDINGS TRLC_CPP17
436 #endif
437 
438 #ifdef __cpp_if_constexpr
439  #if __cpp_if_constexpr >= 201606L
440  #define TRLC_HAS_IF_CONSTEXPR 1
441  #else
442  #define TRLC_HAS_IF_CONSTEXPR 0
443  #endif
444 #else
445  #define TRLC_HAS_IF_CONSTEXPR TRLC_CPP17
446 #endif
447 
448 #ifdef __cpp_concepts
449  #if __cpp_concepts >= 201907L
450  #define TRLC_HAS_CONCEPTS 1
451  #else
452  #define TRLC_HAS_CONCEPTS 0
453  #endif
454 #else
455  #define TRLC_HAS_CONCEPTS TRLC_CPP20
456 #endif
457 
458 #ifdef __cpp_impl_coroutine
459  #if __cpp_impl_coroutine >= 201902L
460  #define TRLC_HAS_COROUTINES 1
461  #else
462  #define TRLC_HAS_COROUTINES 0
463  #endif
464 #elif defined(__cpp_coroutines)
465  #if __cpp_coroutines >= 201902L
466  #define TRLC_HAS_COROUTINES 1
467  #else
468  #define TRLC_HAS_COROUTINES 0
469  #endif
470 #else
471  #define TRLC_HAS_COROUTINES TRLC_CPP20
472 #endif
473 
474 #ifdef __cpp_modules
475  #if __cpp_modules >= 201907L
476  #define TRLC_HAS_MODULES 1
477  #else
478  #define TRLC_HAS_MODULES 0
479  #endif
480 #else
481  #define TRLC_HAS_MODULES 0 // Conservative - modules support varies
482 #endif
483 
484 #ifdef __cpp_lib_ranges
485  #if __cpp_lib_ranges >= 201911L
486  #define TRLC_HAS_RANGES 1
487  #else
488  #define TRLC_HAS_RANGES 0
489  #endif
490 #else
491  #define TRLC_HAS_RANGES TRLC_CPP20
492 #endif
493 
494 #ifdef __cpp_fold_expressions
495  #if __cpp_fold_expressions >= 201603L
496  #define TRLC_HAS_FOLD_EXPRESSIONS 1
497  #else
498  #define TRLC_HAS_FOLD_EXPRESSIONS 0
499  #endif
500 #else
501  #define TRLC_HAS_FOLD_EXPRESSIONS TRLC_CPP17
502 #endif
503 
504 #ifdef __cpp_consteval
505  #if __cpp_consteval >= 201811L
506  #define TRLC_HAS_CONSTEVAL 1
507  #else
508  #define TRLC_HAS_CONSTEVAL 0
509  #endif
510 #else
511  #define TRLC_HAS_CONSTEVAL TRLC_CPP20
512 #endif
513 
514 // Conditional compilation helpers
515 #if TRLC_CPP17
516  #define TRLC_IF_CPP17(code) code
517 #else
518  #define TRLC_IF_CPP17(code)
519 #endif
520 
521 #if TRLC_CPP20
522  #define TRLC_IF_CPP20(code) code
523 #else
524  #define TRLC_IF_CPP20(code)
525 #endif
526 
527 #if TRLC_CPP23
528  #define TRLC_IF_CPP23(code) code
529 #else
530  #define TRLC_IF_CPP23(code)
531 #endif
532 
533 // Constexpr utility macros
534 #if TRLC_HAS_IF_CONSTEXPR
535  #define TRLC_CONSTEXPR_IF(...) if constexpr (__VA_ARGS__)
536 #else
537  #define TRLC_CONSTEXPR_IF(...) if (__VA_ARGS__)
538 #endif
539 
540 // Feature-specific conditional compilation
541 #if TRLC_HAS_STRUCTURED_BINDINGS
542  #define TRLC_IF_STRUCTURED_BINDINGS(code) code
543 #else
544  #define TRLC_IF_STRUCTURED_BINDINGS(code)
545 #endif
546 
547 #if TRLC_HAS_CONCEPTS
548  #define TRLC_IF_CONCEPTS(code) code
549 #else
550  #define TRLC_IF_CONCEPTS(code)
551 #endif
552 
553 #if TRLC_HAS_COROUTINES
554  #define TRLC_IF_COROUTINES(code) code
555 #else
556  #define TRLC_IF_COROUTINES(code)
557 #endif
558 
559 #if TRLC_HAS_RANGES
560  #define TRLC_IF_RANGES(code) code
561 #else
562  #define TRLC_IF_RANGES(code)
563 #endif
564 
565 // Standard library feature availability
566 #if TRLC_CPP17
567  #define TRLC_HAS_STRING_VIEW 1
568  #define TRLC_HAS_OPTIONAL 1
569  #define TRLC_HAS_VARIANT 1
570  #define TRLC_HAS_ANY 1
571  #define TRLC_HAS_FILESYSTEM 1
572 #else
573  #define TRLC_HAS_STRING_VIEW 0
574  #define TRLC_HAS_OPTIONAL 0
575  #define TRLC_HAS_VARIANT 0
576  #define TRLC_HAS_ANY 0
577  #define TRLC_HAS_FILESYSTEM 0
578 #endif
579 
580 #if TRLC_CPP20
581  #define TRLC_HAS_SPAN 1
582  #define TRLC_HAS_FORMAT 1
583  #define TRLC_HAS_CONCEPTS_LIB 1
584  #define TRLC_HAS_CHRONO_CALENDAR 1
585 #else
586  #define TRLC_HAS_SPAN 0
587  #define TRLC_HAS_FORMAT 0
588  #define TRLC_HAS_CONCEPTS_LIB 0
589  #define TRLC_HAS_CHRONO_CALENDAR 0
590 #endif
static CppStandard detectCppStandard()
Detects C++ standard using __cplusplus macro.
static long getCppVersionMacroValue()
Gets the __cplusplus macro value.
static const char * getCppStandardName()
Gets human-readable standard name.
static bool hasThreeWayComparison()
Checks if three-way comparison (spaceship operator) is supported (C++20)
CppStandard
C++ standard enumeration.
@ cpp_unknown
Unknown or unsupported standard.
@ cpp_pre_17
Pre-C++17 standards (C++98/03/11/14)
@ cpp_26
C++26 standard (tentative)
static bool isCpp20OrLater()
Checks if the current C++ standard is at least C++20.
static long getCppVersionMacro()
Gets the __cplusplus macro value.
static bool hasStructuredBindings()
Checks if structured bindings are supported (C++17)
static bool hasRanges()
Checks if ranges library is supported (C++20)
static bool hasConsteval()
Checks if consteval is supported (C++20)
static bool hasConcepts()
Checks if concepts are supported (C++20)
static bool hasInlineVariables()
Checks if inline variables are supported (C++17)
static CppStandard getCppStandard()
Gets the current C++ standard version.
static CppStandardInfo getCppStandardInfo()
Gets comprehensive C++ standard information.
static bool hasModules()
Checks if modules are supported (C++20)
static bool isExactlyCpp23()
Checks if the current C++ standard is exactly C++23.
static bool isExactlyCpp17()
Checks if the current C++ standard is exactly C++17.
static bool hasDesignatedInitializers()
Checks if designated initializers are supported (C++20)
static bool hasIfConstexpr()
Checks if if constexpr is supported (C++17)
static bool isExactlyCpp20()
Checks if the current C++ standard is exactly C++20.
static bool hasFoldExpressions()
Checks if fold expressions are supported (C++17)
static bool hasCoroutines()
Checks if coroutines are supported (C++20)
static bool hasConstinit()
Checks if constinit is supported (C++20)
static bool isCpp17OrLater()
Checks if the current C++ standard is at least C++17.
static bool isCpp23OrLater()
Checks if the current C++ standard is at least C++23.
C++ standard information structure.
const char * standard_name
Human-readable standard name.
long version_macro
Value of __cplusplus macro.
static bool supportsFeature(const char *feature_name) const
Checks if a specific language feature is supported.
CppStandard standard
Detected C++ standard.
static bool isAtLeast(CppStandard min_standard) const
Checks if the current standard is at least the specified version.