inline_variable.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // Copyright 2017 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef Y_ABSL_BASE_INTERNAL_INLINE_VARIABLE_H_
  15. #define Y_ABSL_BASE_INTERNAL_INLINE_VARIABLE_H_
  16. #include <type_traits>
  17. #include "y_absl/base/internal/identity.h"
  18. // File:
  19. // This file define a macro that allows the creation of or emulation of C++17
  20. // inline variables based on whether or not the feature is supported.
  21. ////////////////////////////////////////////////////////////////////////////////
  22. // Macro: Y_ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init)
  23. //
  24. // Description:
  25. // Expands to the equivalent of an inline constexpr instance of the specified
  26. // `type` and `name`, initialized to the value `init`. If the compiler being
  27. // used is detected as supporting actual inline variables as a language
  28. // feature, then the macro expands to an actual inline variable definition.
  29. //
  30. // Requires:
  31. // `type` is a type that is usable in an extern variable declaration.
  32. //
  33. // Requires: `name` is a valid identifier
  34. //
  35. // Requires:
  36. // `init` is an expression that can be used in the following definition:
  37. // constexpr type name = init;
  38. //
  39. // Usage:
  40. //
  41. // // Equivalent to: `inline constexpr size_t variant_npos = -1;`
  42. // Y_ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
  43. //
  44. // Differences in implementation:
  45. // For a direct, language-level inline variable, decltype(name) will be the
  46. // type that was specified along with const qualification, whereas for
  47. // emulated inline variables, decltype(name) may be different (in practice
  48. // it will likely be a reference type).
  49. ////////////////////////////////////////////////////////////////////////////////
  50. #ifdef __cpp_inline_variables
  51. // Clang's -Wmissing-variable-declarations option erroneously warned that
  52. // inline constexpr objects need to be pre-declared. This has now been fixed,
  53. // but we will need to support this workaround for people building with older
  54. // versions of clang.
  55. //
  56. // Bug: https://bugs.llvm.org/show_bug.cgi?id=35862
  57. //
  58. // Note:
  59. // identity_t is used here so that the const and name are in the
  60. // appropriate place for pointer types, reference types, function pointer
  61. // types, etc..
  62. #if defined(__clang__)
  63. #define Y_ABSL_INTERNAL_EXTERN_DECL(type, name) \
  64. extern const ::y_absl::internal::identity_t<type> name;
  65. #else // Otherwise, just define the macro to do nothing.
  66. #define Y_ABSL_INTERNAL_EXTERN_DECL(type, name)
  67. #endif // defined(__clang__)
  68. // See above comment at top of file for details.
  69. #define Y_ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init) \
  70. Y_ABSL_INTERNAL_EXTERN_DECL(type, name) \
  71. inline constexpr ::y_absl::internal::identity_t<type> name = init
  72. #else
  73. // See above comment at top of file for details.
  74. //
  75. // Note:
  76. // identity_t is used here so that the const and name are in the
  77. // appropriate place for pointer types, reference types, function pointer
  78. // types, etc..
  79. #define Y_ABSL_INTERNAL_INLINE_CONSTEXPR(var_type, name, init) \
  80. template <class /*AbslInternalDummy*/ = void> \
  81. struct AbslInternalInlineVariableHolder##name { \
  82. static constexpr ::y_absl::internal::identity_t<var_type> kInstance = init; \
  83. }; \
  84. \
  85. template <class AbslInternalDummy> \
  86. constexpr ::y_absl::internal::identity_t<var_type> \
  87. AbslInternalInlineVariableHolder##name<AbslInternalDummy>::kInstance; \
  88. \
  89. static constexpr const ::y_absl::internal::identity_t<var_type>& \
  90. name = /* NOLINT */ \
  91. AbslInternalInlineVariableHolder##name<>::kInstance; \
  92. static_assert(sizeof(void (*)(decltype(name))) != 0, \
  93. "Silence unused variable warnings.")
  94. #endif // __cpp_inline_variables
  95. #endif // Y_ABSL_BASE_INTERNAL_INLINE_VARIABLE_H_