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__ )
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 && ( defined( __GXX_EXPERIMENTAL_CXX0X__ ) || __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_IF_HAS_RVAL_REFS( x ) x
185 # define DISTI_IF_HAS_RVAL_REFS_ELSE( x, y ) x
186 #else
187 # undef DISTI_HAS_RVAL_REFS
188 # define DISTI_RVAL_MOVE( x ) x
189 # define DISTI_IF_HAS_RVAL_REFS( x )
190 # define DISTI_IF_HAS_RVAL_REFS_ELSE( x, y ) y
191 #endif
192 
193 ///////////////////////////////////////////////////////////////////////////////////////////////////
194 #if !defined( DISTI_NO_METHOD_OVERRIDE ) && defined( DISTI_HAS_METHOD_OVERRIDE )
195 // Add this to the end of an overridden method
196 # define DISTI_METHOD_OVERRIDE override
197 // Add this to the end of a method that should not be overridden
198 # define DISTI_METHOD_FINAL final
199 #else
200 # undef DISTI_HAS_METHOD_OVERRIDE
201 # define DISTI_METHOD_OVERRIDE
202 # define DISTI_METHOD_FINAL
203 #endif
204 
205 ///////////////////////////////////////////////////////////////////////////////////////////////////
206 #if !defined( DISTI_NO_NOEXCEPT ) && defined( DISTI_HAS_NOEXCEPT )
207 // Add this to the end of the method that is guaranteed not to throw
208 # define DISTI_FUNC_NOEXCEPT noexcept
209 #else
210 # undef DISTI_HAS_NOEXCEPT
211 # define DISTI_FUNC_NOEXCEPT
212 #endif
213 
214 ///////////////////////////////////////////////////////////////////////////////////////////////////
215 #if !defined( DISTI_NO_SPECIAL_MEM_FUN_DEL ) && defined( DISTI_HAS_SPECIAL_MEM_FUN_DEL )
216 // Add these to the end of special member functions to delete them.
217 # define DISTI_SPECIAL_MEM_FUN_DELETE = delete
218 #else
219 # undef DISTI_HAS_SPECIAL_MEM_FUN_DEL
220 # define DISTI_SPECIAL_MEM_FUN_DELETE
221 #endif
222 
223 ///////////////////////////////////////////////////////////////////////////////////////////////////
224 #if !defined( DISTI_NO_USER_DEFINED_LITERALS ) && defined( DISTI_HAS_USER_DEFINED_LITERALS )
225 # define DISTI_IF_HAS_USER_DEFINED_LITERAL( x ) x
226 #else
227 # undef DISTI_HAS_USER_DEFINED_LITERALS
228 # define DISTI_IF_HAS_USER_DEFINED_LITERAL( x )
229 #endif
230 
231 ///////////////////////////////////////////////////////////////////////////////////////////////////
232 #if !defined( DISTI_NO_TYPE_TRAITS ) && defined( DISTI_HAS_TYPE_TRAITS )
233 // Use this by including <type_traits> and then providing a default, e.g.,
234 // DISTI_IF_HAS_TYPE_TRAITS_ELSE( std::is_const<T>::value, false )
235 # define DISTI_IF_HAS_TYPE_TRAITS_ELSE( x, y ) x
236 #else
237 # undef DISTI_HAS_TYPE_TRAITS
238 # define DISTI_IF_HAS_TYPE_TRAITS_ELSE( x, y ) y
239 
240 namespace disti
241 {
242 // The _cppLangSupportDetail namespace is here to hide implementation details, mostly for things
243 // that are standard but not available on all supported platforms.
244 namespace _cppLangSupportDetail
245 {
246  /// Replacement for std::is_convertible, adapted from Loki 0.1.7.
247  /////////////////////////////////////////////////////////////////////////////////
248  /// \copyright The Loki Library, Copyright (c) 2001 by Andrei Alexandrescu<br />
249  /// This code accompanies the book:
250  /// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
251  /// Patterns Applied". Copyright (c) 2001. Addison-Wesley.<br />
252  /// Permission to use, copy, modify, distribute and sell this software for any
253  /// purpose is hereby granted without fee, provided that the above copyright
254  /// notice appear in all copies and that both that copyright notice and this
255  /// permission notice appear in supporting documentation.<br />
256  /// The author or Addison-Welsey Longman make no representations about the
257  /// suitability of this software for any purpose. It is provided "as is"
258  /// without express or implied warranty.<br />
259  /////////////////////////////////////////////////////////////////////////////////
260  template<class T, class U>
262  {
263  private:
264  typedef char Small;
265  struct Big
266  {
267  char dummy[ 2 ];
268  };
269  static Big Test( ... );
270  static Small Test( U );
271  static T MakeT();
272 
273  public:
274  enum
275  {
276  value = sizeof( Small ) == sizeof( ( Test( MakeT() ) ) )
277  };
278  };
279 
280  template<class T>
281  struct is_convertible<T, T>
282  {
283  enum
284  {
285  value = true
286  };
287  }; //< Replacement for std::is_convertible, adapted from Loki 0.1.7.
288  template<class T>
289  struct is_convertible<void, T>
290  {
291  enum
292  {
293  value = false
294  };
295  }; //< Replacement for std::is_convertible, adapted from Loki 0.1.7.
296  template<class T>
297  struct is_convertible<T, void>
298  {
299  enum
300  {
301  value = false
302  };
303  }; //< Replacement for std::is_convertible, adapted from Loki 0.1.7.
304  template<>
305  struct is_convertible<void, void>
306  {
307  enum
308  {
309  value = true
310  };
311  }; //< Replacement for std::is_convertible, adapted from Loki 0.1.7.
312 } // namespace _cppLangSupportDetail
313 } // namespace disti
314 #endif
315 
316 ///////////////////////////////////////////////////////////////////////////////////////////////////
317 #if defined( DISTI_NO_STATIC_ASSERT )
318 # undef DISTI_HAS_STATIC_ASSERT
319 # define DISTI_STATIC_ASSERT( expr, msg )
320 #else
321 # define DISTI_PREPROC_STRINGIFY_HELPER( s ) # s
322 # define DISTI_PREPROC_STRINGIFY( s ) DISTI_PREPROC_STRINGIFY_HELPER( s )
323 
324 # if defined( DISTI_HAS_STATIC_ASSERT )
325  /// \brief Uses C++11's static_assert() because it is available on this platform.
326  /// \param expr a compile-time integral or pointer expression
327  /// \param msg a C identifier that will appear in compiler diagnostics
328  /// \note For older compilers' benefit, \a msg should be a C identifier such as:
329  /// \code{.cpp}
330  /// DISTI_STATIC_ASSERT( (std::is_convertible<T*,ConvertsTo*>::value), class_does_not_inherit_from_##ConvertsTo )
331  /// \endcode
332  /// which shows a compile-time error that typically includes: "ERROR_class_does_not_inherit_from_Group".
333  /// If it is not a C identifier, you may get spurious error messages at compile time compilers without static_assert.
334 # define DISTI_STATIC_ASSERT( expr, msg ) static_assert( expr, DISTI_PREPROC_STRINGIFY( msg ) )
335 # else
336 namespace disti
337 {
338 namespace _cppLangSupportDetail
339 {
340  // Helpers for DISTI_STATIC_ASSERT
341  // \note Adapted from Loki 0.1.7.
342  template<int>
344  template<>
345  struct CompileTimeError<true>
346  {
347  CompileTimeError() {}
348  };
349 } // namespace _cppLangSupportDetail
350 } // namespace disti
351 
352  /// \brief Poor man's version of C++11's static_assert()
353  /// \param expr a compile-time integral or pointer expression
354  /// \param msg a C identifier that will appear in compiler diagnostics
355  /// \note For older compilers' benefit, \a msg should be a C identifier such as:
356  /// \code{.cpp}
357  /// DISTI_STATIC_ASSERT( (std::is_convertible<T*,ConvertsTo*>::value), class_does_not_inherit_from_##ConvertsTo )
358  /// \endcode
359  /// which shows a compile-time error that typically includes: "ERROR_class_does_not_inherit_from_Group".
360  /// If it is not a C identifier, you may get spurious error messages at compile time compilers without static_assert.
361  /// \note Adapted from Loki 0.1.7.
362 # define DISTI_STATIC_ASSERT( expr, msg ) \
363  { \
364  ::disti::_cppLangSupportDetail::CompileTimeError<( ( expr ) != 0 )> ERROR_##msg; \
365  (void)ERROR_##msg; \
366  }
367 # endif
368 #endif
369 
370 ////////////////////////////////////////////////////////////////////////////////
371 /// Convenience macro to check that one type converts to another at compile-time.
372 /// \param T A class to check
373 /// \param ConvertsTo A class to test T* against to verify that it can be
374 /// converted to ConvertsTo* without a cast.
375 /// \note This macro appears here for grouping with like code, but macros
376 /// aren't scoped to namespace.
377 ////////////////////////////////////////////////////////////////////////////////
378 #ifdef DISTI_HAS_TYPE_TRAITS
379 # define DISTI_STATIC_ASSERT_IS_CONVERTIBLE_TO( T, ConvertsTo ) DISTI_STATIC_ASSERT( ( std::is_convertible<T*, ConvertsTo*>::value ), class_does_not_inherit_from_##ConvertsTo );
380 #else
381 # 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 )
382 #endif
383 
384 /// Defines whether this compiler supports the C++14 deprecated attribute
385 #if defined( DISTI_HAS_DEPRECATED_ATTRIBUTE ) && !defined( DISTI_NO_DEPRECATED_ATTRIBUTE )
386 # define DISTI_DEPRECATED( msg ) [[deprecated( msg )]]
387 #else
388 # define DISTI_DEPRECATED( msg )
389 #endif
390 
391 ////////////////////////////////////////////////////////////////////////////////
392 // Since not all platforms support C++11, we provide an equivalent feature here that does not require it.
393 // Formulae derived from the proposal for std::numeric_limits<>::max_digits10 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2005.pdf)
394 ////////////////////////////////////////////////////////////////////////////////
395 #include <float.h>
396 namespace disti
397 {
398 // clang-format off
399 template<class T> struct MaxDigits10 { static const unsigned long value = 0; };
400 template<> struct MaxDigits10<float> { static const unsigned long value = 2 + (FLT_MANT_DIG * 30103UL) / 100000UL; };
401 template<> struct MaxDigits10<double> { static const unsigned long value = 2 + (DBL_MANT_DIG * 30103UL) / 100000UL; };
402 template<> struct MaxDigits10<long double> { static const unsigned long value = 2 + (LDBL_MANT_DIG * 30103UL) / 100000UL; };
403 // clang-format on
404 } // namespace disti
405 
406 #endif
Replacement for std::is_convertible, adapted from Loki 0.1.7.
Definition: gls_cpp_lang_support.h:261
Definition: gls_cpp_lang_support.h:343
Definition: gls_cpp_lang_support.h:399
Definition: bmpimage.h:46