GL Studio C++ Runtime API
gls_cpp_lang_support.h
Go to the documentation of this file.
1 /*! \file
2  \brief Macros and helper code to determine what subset of C++11/14/17 is available.
3 
4  \par Copyright Information
5 
6  Copyright (c) 2016 The DiSTI Corporation.<br>
7  11486 Corporate Blvd; Suite 190<br>
8  Orlando, Florida 32817<br>
9  USA<br>
10  <br>
11  All rights reserved.<br>
12 
13  This Software contains proprietary trade secrets of DiSTI and may not be
14 reproduced, in whole or part, in any form, or by any means of electronic,
15 mechanical, or otherwise, without the written permission of DiSTI. Said
16 permission may be derived through the purchase of applicable DiSTI product
17 licenses which detail the distribution rights of this content and any
18 Derivative Works based on this or other copyrighted DiSTI Software.
19 
20  NO WARRANTY. THE SOFTWARE IS PROVIDED "AS-IS," WITHOUT WARRANTY OF ANY KIND,
21 AND ANY USE OF THIS SOFTWARE PRODUCT IS AT YOUR OWN RISK. TO THE MAXIMUM EXTENT
22 PERMITTED BY APPLICABLE LAW, DISTI AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES
23 AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
24 IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY AND/OR FITNESS FOR A
25 PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT, WITH REGARD TO THE SOFTWARE.
26 
27  LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW,
28 IN NO EVENT SHALL DISTI OR ITS SUPPLIERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
29 INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION,
30 DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS
31 INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR
32 INABILITY TO USE THE SOFTWARE, EVEN IF DISTI HAS BEEN ADVISED OF THE POSSIBILITY
33 OF SUCH DAMAGES. DISTI'S ENTIRE LIABILITY AND YOUR EXCLUSIVE REMEDY SHALL NOT
34 EXCEED FIVE DOLLARS (US$5.00).
35 
36  The aforementioned terms and restrictions are governed by the laws of the
37 State of Florida and the United States of America.
38 */
39 
40 #ifndef INCLUDED_GLS_CPP_LANG_SUPPORT_H
41 #define INCLUDED_GLS_CPP_LANG_SUPPORT_H
42 
43 // Conditional C++11/14 support
44 //
45 // We use a subset of C++11/14 features to improve efficiency and correctness of code.
46 //
47 // We attempt to detect compiler support, but for unusual configurations, it can be
48 // enabled with project-level defines. Define DISTI_HAS_CPP11 to enable all features.
49 // Enable specific features by defining any of the following:
50 //
51 // DISTI_HAS_RVAL_REFS // For rvalue references
52 // DISTI_HAS_METHOD_OVERRIDE // For "override" and "final" keywords
53 // DISTI_HAS_NOEXCEPT // For "noexcept" keyword
54 // DISTI_HAS_SPECIAL_MEM_FUN_DEL // For "= delete"
55 // DISTI_HAS_TYPE_TRAITS // For compile-time checking via type-traits
56 // DISTI_HAS_STATIC_ASSERT // For static_assert support
57 // DISTI_HAS_DEPRECATED_ATTRIBUTE // For [[deprecated("why")]] attribute
58 // DISTI_HAS_USER_DEFINED_LITERALS // For operator""_myLiteral
59 //
60 // If our detection is incorrect, override it with a corresponding "NO" define:
61 //
62 // DISTI_NO_RVAL_REFS // For rvalue references
63 // DISTI_NO_METHOD_OVERRIDE // For "override" and "final" keywords
64 // DISTI_NO_NOEXCEPT // For "noexcept" keyword
65 // DISTI_NO_SPECIAL_MEM_FUN_DEL // For "= delete"
66 // DISTI_NO_TYPE_TRAITS // For compile-time checking via type-traits
67 // DISTI_NO_STATIC_ASSERT // For static_assert support
68 // DISTI_NO_DEPRECATED_ATTRIBUTE // For [[deprecated("why")]] attribute
69 // DISTI_NO_USER_DEFINED_LITERALS // For operator""_myLiteral
70 /////////////////////////////////////////////////////////////////////////////////////
71 // Microsoft C++ Compiler -- https://msdn.microsoft.com/en-us/library/hh567368.aspx
72 /////////////////////////////////////////////////////////////////////////////////////
73 #if defined( _MSC_VER )
74 # if _MSC_VER >= 1700 // >= VS2012
75 # define DISTI_HAS_RVAL_REFS
76 # define DISTI_HAS_METHOD_OVERRIDE
77 # define DISTI_HAS_TYPE_TRAITS
78 # define DISTI_HAS_STATIC_ASSERT
79 # endif
80 # if _MSC_VER >= 1800 // >= VS2013
81 # define DISTI_HAS_SPECIAL_MEM_FUN_DEL
82 # define DISTI_HAS_CPP11
83 # endif
84 # if _MSC_VER >= 1900 // >= VS2015
85 # define DISTI_HAS_USER_DEFINED_LITERALS
86 # endif
87 # if _MSC_VER >= 1911 && __cplusplus >= 201402L // >= VS2017 15.3
88 # define DISTI_HAS_NOEXCEPT
89 # define DISTI_HAS_DEPRECATED_ATTRIBUTE
90 # define DISTI_HAS_CPP14
91 # endif
92 
93 ////////////////////////////////////////////////////////////////////////////////
94 // GCC versions -- https://gcc.gnu.org/projects/cxx-status.html#cxx11
95 ////////////////////////////////////////////////////////////////////////////////
96 #elif defined( __GNUC__ ) && !defined( __clang__ )
97 // __cpp_rvalue_references doesn't seem to be defined in GCC, despite the documentation, so we have an alternative check also
98 # if __cpp_rvalue_references >= 200610 || ( ( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3 ) ) && ( defined( __GXX_EXPERIMENTAL_CXX0X__ ) || __cplusplus >= 201103L ) )
99 # define DISTI_HAS_RVAL_REFS
100 # endif
101 # if __cpp_static_assert >= 200410 && ( defined( __GXX_EXPERIMENTAL_CXX0X__ ) || __cplusplus >= 201103L )
102 # define DISTI_HAS_STATIC_ASSERT
103 # endif
104 # if( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 9 ) ) && ( defined( __GXX_EXPERIMENTAL_CXX0X__ ) || __cplusplus >= 201103L )
105 # define DISTI_HAS_USER_DEFINED_LITERALS
106 # endif
107 # if( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 7 ) ) && ( defined( __GXX_EXPERIMENTAL_CXX0X__ ) || __cplusplus >= 201103L )
108 # define DISTI_HAS_METHOD_OVERRIDE
109 # define DISTI_HAS_NOEXCEPT
110 # define DISTI_HAS_TYPE_TRAITS // This actually depends on which standard library is in use, but it's a safe bet.
111 # define DISTI_HAS_CPP11
112 # endif
113 # if( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 4 ) ) && ( defined( __GXX_EXPERIMENTAL_CXX0X__ ) || __cplusplus >= 201103L )
114 # define DISTI_HAS_SPECIAL_MEM_FUN_DEL
115 # endif
116 # if( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 9 ) ) && __cplusplus >= 201402L
117 # define DISTI_HAS_DEPRECATED_ATTRIBUTE
118 # define DISTI_HAS_CPP14
119 # endif
120 
121 ////////////////////////////////////////////////////////////////////////////////
122 // Clang versions -- http://clang.llvm.org/cxx_status.html
123 ////////////////////////////////////////////////////////////////////////////////
124 #elif defined( __clang__ )
125 # if __has_feature( cxx_rvalue_references )
126 # define DISTI_HAS_RVAL_REFS
127 # define DISTI_HAS_CPP11 // Guess that if we have rvalue refs, we've got pretty solid C++11 support
128 # endif
129 # if __has_feature( cxx_override_control )
130 # define DISTI_HAS_METHOD_OVERRIDE
131 # endif
132 # if __has_feature( cxx_noexcept )
133 # define DISTI_HAS_NOEXCEPT
134 # endif
135 # if __has_feature( cxx_defaulted_functions ) && __has_feature( cxx_deleted_functions )
136 # define DISTI_HAS_SPECIAL_MEM_FUN_DEL
137 # endif
138 # if __has_feature( cxx_static_assert )
139 # define DISTI_HAS_STATIC_ASSERT
140 # endif
141 # if __has_feature( cxx_user_literals )
142 # define DISTI_HAS_USER_DEFINED_LITERALS
143 # endif
144 # if( __clang_major__ > 3 || ( __clang_major__ == 3 && __clang_minor__ >= 4 ) ) && __cplusplus >= 201402L
145 # define DISTI_HAS_DEPRECATED_ATTRIBUTE
146 # define DISTI_HAS_CPP14
147 # endif
148 // This actually depends on which standard library is in use, but it's a safe bet.
149 # define DISTI_HAS_TYPE_TRAITS
150 #endif
151 
152 ///////////////////////////////////////////////////////////////////////////////////////////////////
153 // Shortcut for unrecognized compilers
154 ///////////////////////////////////////////////////////////////////////////////////////////////////
155 // A single switch to enable everything since compiler is highly compliant
156 // These macros can help with cross-platform portability
157 #ifdef DISTI_HAS_CPP14
158 # define DISTI_HAS_CPP11
159 # define DISTI_HAS_DEPRECATED_ATTRIBUTE
160 #endif
161 
162 #ifdef DISTI_HAS_CPP11
163 # define DISTI_IF_HAS_CPP11( x ) x
164 # define DISTI_IF_HAS_CPP11_ELSE( x, y ) x
165 
166 # define DISTI_HAS_RVAL_REFS
167 # define DISTI_HAS_METHOD_OVERRIDE
168 # define DISTI_HAS_SPECIAL_MEM_FUN_DEL
169 # define DISTI_HAS_TYPE_TRAITS
170 # define DISTI_HAS_STATIC_ASSERT
171 #else
172 // Not fully C++11; some features may be enabled piecemeal
173 // These macros can help with cross-platform portability
174 # define DISTI_IF_HAS_CPP11( x )
175 # define DISTI_IF_HAS_CPP11_ELSE( x, y ) y
176 #endif
177 
178 ///////////////////////////////////////////////////////////////////////////////////////////////////
179 // Individual C++11 features. See comment above on DISTI_NO_* vs. DISTI_HAS_* macros.
180 ///////////////////////////////////////////////////////////////////////////////////////////////////
181 #if !defined( DISTI_NO_RVAL_REFS ) && defined( DISTI_HAS_RVAL_REFS )
182 # include <utility>
183 # define DISTI_RVAL_MOVE( x ) std::move( x )
184 # define DISTI_UREF_FORWARD( T, x ) std::forward<T>( x )
185 # define DISTI_UREF( T ) T&&
186 # define DISTI_IF_HAS_RVAL_REFS( x ) x
187 # define DISTI_IF_HAS_RVAL_REFS_ELSE( x, y ) x
188 #else
189 # undef DISTI_HAS_RVAL_REFS
190 # define DISTI_RVAL_MOVE( x ) x
191 # define DISTI_UREF_FORWARD( T, x ) x
192 # define DISTI_UREF( T ) const T&
193 # define DISTI_IF_HAS_RVAL_REFS( x )
194 # define DISTI_IF_HAS_RVAL_REFS_ELSE( x, y ) y
195 #endif
196 
197 ///////////////////////////////////////////////////////////////////////////////////////////////////
198 #if !defined( DISTI_NO_METHOD_OVERRIDE ) && defined( DISTI_HAS_METHOD_OVERRIDE )
199 // Add this to the end of an overridden method
200 # define DISTI_METHOD_OVERRIDE override
201 // Add this to the end of a method or class that should not be overridden
202 # define DISTI_FINAL final
203 #else
204 # undef DISTI_HAS_METHOD_OVERRIDE
205 # define DISTI_METHOD_OVERRIDE
206 # define DISTI_FINAL
207 #endif
208 
209 ///////////////////////////////////////////////////////////////////////////////////////////////////
210 #if !defined( DISTI_NO_NOEXCEPT ) && defined( DISTI_HAS_NOEXCEPT )
211 // Add this to the end of the method that is guaranteed not to throw
212 # define DISTI_FUNC_NOEXCEPT noexcept
213 #else
214 # undef DISTI_HAS_NOEXCEPT
215 # define DISTI_FUNC_NOEXCEPT
216 #endif
217 
218 ///////////////////////////////////////////////////////////////////////////////////////////////////
219 #if !defined( DISTI_NO_SPECIAL_MEM_FUN_DEL ) && defined( DISTI_HAS_SPECIAL_MEM_FUN_DEL )
220 // Add these to the end of special member functions to delete them.
221 # define DISTI_SPECIAL_MEM_FUN_DELETE = delete
222 #else
223 # undef DISTI_HAS_SPECIAL_MEM_FUN_DEL
224 # define DISTI_SPECIAL_MEM_FUN_DELETE
225 #endif
226 
227 ///////////////////////////////////////////////////////////////////////////////////////////////////
228 #if !defined( DISTI_NO_USER_DEFINED_LITERALS ) && defined( DISTI_HAS_USER_DEFINED_LITERALS )
229 # define DISTI_IF_HAS_USER_DEFINED_LITERAL( x ) x
230 #else
231 # undef DISTI_HAS_USER_DEFINED_LITERALS
232 # define DISTI_IF_HAS_USER_DEFINED_LITERAL( x )
233 #endif
234 
235 ///////////////////////////////////////////////////////////////////////////////////////////////////
236 #if !defined( DISTI_NO_TYPE_TRAITS ) && defined( DISTI_HAS_TYPE_TRAITS )
237 // Use this by including <type_traits> and then providing a default, e.g.,
238 // DISTI_IF_HAS_TYPE_TRAITS_ELSE( std::is_const<T>::value, false )
239 # define DISTI_IF_HAS_TYPE_TRAITS_ELSE( x, y ) x
240 
241 ////////////////////////////////////////////////////////////////////////////////
242 /// Convenience macro to check that one type converts to another at compile-time.
243 /// \param T A class to check
244 /// \param ConvertsTo A class to test T* against to verify that it can be
245 /// converted to ConvertsTo* without a cast.
246 ////////////////////////////////////////////////////////////////////////////////
247 # define DISTI_STATIC_ASSERT_IS_CONVERTIBLE_TO( T, ConvertsTo ) DISTI_STATIC_ASSERT( ( std::is_convertible<T*, ConvertsTo*>::value ), class_does_not_inherit_from_##ConvertsTo );
248 
249 /// Determines if a class \a T is trivially destructible (i.e., has no side effects)
250 # define DISTI_IS_TRIVIALLY_DESTRUCTIBLE( T ) ( std::is_trivially_destructible<T>() )
251 # define DISTI_TT_TRUE_TYPE std::true_type
252 # define DISTI_TT_FALSE_TYPE std::false_type
253 #else
254 # undef DISTI_HAS_TYPE_TRAITS
255 # define DISTI_IF_HAS_TYPE_TRAITS_ELSE( x, y ) y
256 
257 // See documentation above
258 # define DISTI_STATIC_ASSERT_IS_CONVERTIBLE_TO( T, ConvertsTo ) DISTI_STATIC_ASSERT( ( ::disti::_cppLangSupportDetail::is_convertible<T*, ConvertsTo*>::value ), class_does_not_inherit_from_##ConvertsTo )
259 
260 // See documentation above
261 # define DISTI_IS_TRIVIALLY_DESTRUCTIBLE( T ) ( ::disti::_cppLangSupportDetail::is_trivially_destructible<T>() )
262 # define DISTI_TT_TRUE_TYPE ::disti::_cppLangSupportDetail::true_type
263 # define DISTI_TT_FALSE_TYPE ::disti::_cppLangSupportDetail::false_type
264 
265 namespace disti
266 {
267 // The _cppLangSupportDetail namespace is here to hide implementation details, mostly for things
268 // that are standard but not available on all supported platforms.
269 namespace _cppLangSupportDetail
270 {
271  /// Replacement for std::is_convertible, adapted from Loki 0.1.7.
272  /////////////////////////////////////////////////////////////////////////////////
273  /// \copyright The Loki Library, Copyright (c) 2001 by Andrei Alexandrescu<br />
274  /// This code accompanies the book:
275  /// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
276  /// Patterns Applied". Copyright (c) 2001. Addison-Wesley.<br />
277  /// Permission to use, copy, modify, distribute and sell this software for any
278  /// purpose is hereby granted without fee, provided that the above copyright
279  /// notice appear in all copies and that both that copyright notice and this
280  /// permission notice appear in supporting documentation.<br />
281  /// The author or Addison-Welsey Longman make no representations about the
282  /// suitability of this software for any purpose. It is provided "as is"
283  /// without express or implied warranty.<br />
284  /////////////////////////////////////////////////////////////////////////////////
285  template<class T, class U>
286  struct is_convertible
287  {
288  private:
289  typedef char Small;
290  struct Big
291  {
292  char dummy[ 2 ];
293  };
294  static Big Test( ... );
295  static Small Test( U );
296  static T MakeT();
297 
298  public:
299  enum
300  {
301  value = sizeof( Small ) == sizeof( ( Test( MakeT() ) ) )
302  };
303  };
304 
305  // clang-format off
306  template<class T> struct is_convertible<T, T > { enum { value = true }; }; //< Replacement for std::is_convertible, adapted from Loki 0.1.7.
307  template<class T> struct is_convertible<void, T > { enum { value = false }; }; //< Replacement for std::is_convertible, adapted from Loki 0.1.7.
308  template<class T> struct is_convertible<T, void> { enum { value = false }; }; //< Replacement for std::is_convertible, adapted from Loki 0.1.7.
309  template<> struct is_convertible<void, void> { enum { value = true }; }; //< Replacement for std::is_convertible, adapted from Loki 0.1.7.
310 
311 # if defined( DISTI_USER_DEFINED_IS_TRIVIALLY_DESTRUCTIBLE ) // Prefer the user-defined version if available
312 # define DISTI_TT_IS_TRIVIALLY_DESTRUCTIBLE( T ) ( DISTI_USER_DEFINED_IS_TRIVIALLY_DESTRUCTIBLE( T ) )
313 # else
314  // Use compiler intrinsics for something that cannot be reliably determined without it.
315  // Drawn from Boost 1.55.0's implementation.
316 # if defined( _MSC_VER )
317 # define DISTI_TT_IS_TRIVIALLY_DESTRUCTIBLE( T ) ( __has_trivial_destructor( T ) || ( __is_pod( T ) && __has_trivial_constructor( T ) ) )
318 # else
319  // This is defined for all supported versions of GCC and Clang and is also common elsewhere.
320  // Define DISTI_USER_DEFINED_IS_TRIVIALLY_DESTRUCTIBLE() to override.
321 # define DISTI_TT_IS_TRIVIALLY_DESTRUCTIBLE( T ) ( __has_trivial_destructor( T ) )
322 # endif
323 # endif
324 # if defined( DISTI_USER_DEFINED_IS_DESTRUCTIBLE ) // Prefer the user-defined version if available
325 # define DISTI_TT_IS_DESTRUCTIBLE( T ) ( DISTI_USER_DEFINED_IS_DESTRUCTIBLE( T ) )
326 # else
327  // This is defined for all supported versions of GCC and Clang and is also common elsewhere.
328  // Define DISTI_USER_DEFINED_IS_DESTRUCTIBLE() to override.
329 # define DISTI_TT_IS_DESTRUCTIBLE( T ) ( __is_pod( T ) || __is_class( T ) )
330 # endif
331  // clang-format on
332 
333  template<typename T, T Val>
334  struct integral_constant
335  {
336  static const T value;
337  typedef T value_type;
338  typedef integral_constant<T, Val> type;
339  operator value_type() { return value; }
340  };
341 
342  template<typename T, T Val>
343  const T integral_constant<T, Val>::value = Val;
344 
345  typedef integral_constant<bool, true> true_type;
346  typedef integral_constant<bool, false> false_type;
347 
348  template<typename T>
349  struct is_trivially_destructible
350  : integral_constant<bool, DISTI_TT_IS_DESTRUCTIBLE( T ) && DISTI_TT_IS_TRIVIALLY_DESTRUCTIBLE( T )>
351  {};
352 
353 } // namespace _cppLangSupportDetail
354 } // namespace disti
355 #endif
356 
357 ///////////////////////////////////////////////////////////////////////////////////////////////////
358 #if defined( DISTI_NO_STATIC_ASSERT )
359 # undef DISTI_HAS_STATIC_ASSERT
360 # define DISTI_STATIC_ASSERT( expr, msg )
361 #else
362 # define DISTI_PREPROC_STRINGIFY_HELPER( s ) # s
363 # define DISTI_PREPROC_STRINGIFY( s ) DISTI_PREPROC_STRINGIFY_HELPER( s )
364 
365 # if defined( DISTI_HAS_STATIC_ASSERT )
366  /// \brief Uses C++11's static_assert() because it is available on this platform.
367  /// \param expr a compile-time integral or pointer expression
368  /// \param msg a C identifier that will appear in compiler diagnostics
369  /// \note For older compilers' benefit, \a msg should be a C identifier such as:
370  /// \code{.cpp}
371  /// DISTI_STATIC_ASSERT( (std::is_convertible<T*,ConvertsTo*>::value), class_does_not_inherit_from_##ConvertsTo )
372  /// \endcode
373  /// which shows a compile-time error that typically includes: "ERROR_class_does_not_inherit_from_Group".
374  /// If it is not a C identifier, you may get spurious error messages at compile time compilers without static_assert.
375 # define DISTI_STATIC_ASSERT( expr, msg ) static_assert( expr, DISTI_PREPROC_STRINGIFY( msg ) )
376 
377 /// \brief Uses C++11's static_assert() because it is available on this platform.
378 /// \param expr a compile-time integral or pointer expression with a string message.
379 /// \param msg a string to help the developer determine what went wrong.
380 /// \code{.cpp}
381 /// DISTI_STATIC_ASSERT_STR( (std::is_convertible<T*, Base*>::value), "Class does not inherit from Base." );
382 /// \endcode
383 /// \note Adapted from Loki 0.1.7.
384 # define DISTI_STATIC_ASSERT_STR( expr, msg ) static_assert( expr, msg )
385 
386 # else
387 namespace disti
388 {
389 namespace _cppLangSupportDetail
390 {
391  // Helpers for DISTI_STATIC_ASSERT
392  // \note Adapted from Loki 0.1.7.
393  template<int>
394  struct CompileTimeError;
395  template<>
396  struct CompileTimeError<true>
397  {
398  CompileTimeError() {}
399  CompileTimeError( const char* ) {}
400  };
401 } // namespace _cppLangSupportDetail
402 } // namespace disti
403 
404 /// \brief Poor man's version of C++11's static_assert()
405 /// \param expr a compile-time integral or pointer expression
406 /// \param msg a C identifier that will appear in compiler diagnostics
407 /// \note For older compilers' benefit, \a msg should be a C identifier such as:
408 /// \code{.cpp}
409 /// DISTI_STATIC_ASSERT( (std::is_convertible<T*, Base*>::value), class_does_not_inherit_from_Base );
410 /// \endcode
411 /// which shows a compile-time error that typically includes: "ERROR_class_does_not_inherit_from_Base".
412 /// If it is not a C identifier, you may get spurious error messages at compile time compilers without static_assert.
413 /// \note Adapted from Loki 0.1.7.
414 # define DISTI_STATIC_ASSERT( expr, msg ) \
415  { \
416  ::disti::_cppLangSupportDetail::CompileTimeError<( ( expr ) != 0 )> ERROR_##msg; \
417  (void)ERROR_##msg; \
418  }
419 
420 /// \param expr a compile-time integral or pointer expression with a string message
421 /// \param msg a string to help the developer determine what went wrong.
422 /// \code{.cpp}
423 /// DISTI_STATIC_ASSERT_STR( (std::is_convertible<T*, Base*>::value), "Class does not inherit from Base." );
424 /// \endcode
425 /// \note Adapted from Loki 0.1.7.
426 # define DISTI_STATIC_ASSERT_STR( expr, msg ) \
427  { \
428  ::disti::_cppLangSupportDetail::CompileTimeError<( ( expr ) != 0 )> ERROR_##__LINE__( msg ); \
429  (void)ERROR_##__LINE__; \
430  }
431 # endif
432 #endif
433 
434 /// Defines whether this compiler supports the C++14 deprecated attribute
435 #if defined( DISTI_HAS_DEPRECATED_ATTRIBUTE ) && !defined( DISTI_NO_DEPRECATED_ATTRIBUTE )
436 # define DISTI_DEPRECATED( msg ) [[deprecated( msg )]]
437 #else
438 # define DISTI_DEPRECATED( msg )
439 #endif
440 
441 ////////////////////////////////////////////////////////////////////////////////
442 // Since not all platforms support C++11, we provide an equivalent feature here that does not require it.
443 // Formulae derived from the proposal for std::numeric_limits<>::max_digits10 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2005.pdf)
444 ////////////////////////////////////////////////////////////////////////////////
445 #include <float.h>
446 namespace disti
447 {
448 // clang-format off
449 template<class T> struct MaxDigits10 { static const unsigned long value = 0; };
450 template<> struct MaxDigits10<float> { static const unsigned long value = 2 + (FLT_MANT_DIG * 30103UL) / 100000UL; };
451 template<> struct MaxDigits10<double> { static const unsigned long value = 2 + (DBL_MANT_DIG * 30103UL) / 100000UL; };
452 template<> struct MaxDigits10<long double> { static const unsigned long value = 2 + (LDBL_MANT_DIG * 30103UL) / 100000UL; };
453 // clang-format on
454 } // namespace disti
455 
456 #endif
Definition: gls_cpp_lang_support.h:449
Definition: bmpimage.h:46