GL Studio 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 support
44 //
45 // We use a subset of C++11 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_SPECIAL_MEM_FUN_DEL // For "= delete"
54 // DISTI_HAS_TYPE_TRAITS // For compile-time checking via type-traits
55 // DISTI_HAS_STATIC_ASSERT // For static_assert support
56 //
57 // If our detection is incorrect, override it with a corresponding "NO" define:
58 //
59 // DISTI_NO_RVAL_REFS // For rvalue references
60 // DISTI_NO_METHOD_OVERRIDE // For "override" and "final" keywords
61 // DISTI_NO_METHOD_FINAL // For "final" keyword
62 // DISTI_NO_SPECIAL_MEM_FUN_DEL // For "= delete"
63 // DISTI_NO_TYPE_TRAITS // For compile-time checking via type-traits
64 // DISTI_NO_STATIC_ASSERT // For static_assert support
65 
66 /////////////////////////////////////////////////////////////////////////////////////
67 // Microsoft C++ Compiler -- https://msdn.microsoft.com/en-us/library/hh567368.aspx
68 /////////////////////////////////////////////////////////////////////////////////////
69 #if defined(_MSC_VER)
70  #if _MSC_VER >= 1700 // >= VS2012
71  #define DISTI_HAS_RVAL_REFS
72  #define DISTI_HAS_METHOD_OVERRIDE
73  #define DISTI_HAS_TYPE_TRAITS
74  #define DISTI_HAS_STATIC_ASSERT
75  #endif
76  #if _MSC_VER >= 1800 // >= VS2013
77  #define DISTI_HAS_SPECIAL_MEM_FUN_DEL
78  #endif
79 ////////////////////////////////////////////////////////////////////////////////
80 // GCC versions -- https://gcc.gnu.org/projects/cxx-status.html#cxx11
81 ////////////////////////////////////////////////////////////////////////////////
82 #elif defined( __GNUC__ )
83  // __cpp_rvalue_references doesn't seem to be defined in GCC, despite the documentation, so we have an alternative check also
84  #if __cpp_rvalue_references >= 200610 || ( (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && ( defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L ) )
85  #define DISTI_HAS_RVAL_REFS
86  #endif
87  #if __cpp_static_assert >= 200410 && ( defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L )
88  #define DISTI_HAS_STATIC_ASSERT
89  #endif
90  #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && ( defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L )
91  #define DISTI_HAS_METHOD_OVERRIDE
92 
93  // This actually depends on which standard library is in use, but it's a safe bet.
94  #define DISTI_HAS_TYPE_TRAITS
95  #endif
96  #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) && ( defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L )
97  #define DISTI_HAS_SPECIAL_MEM_FUN_DEL
98  #endif
99 ////////////////////////////////////////////////////////////////////////////////
100 // Clang versions -- http://clang.llvm.org/cxx_status.html
101 ////////////////////////////////////////////////////////////////////////////////
102 #elif defined( __clang__ )
103  #if __has_feature(cxx_rvalue_references)
104  #define DISTI_HAS_RVAL_REFS
105  #endif
106  #if __has_feature(cxx_override_control)
107  #define DISTI_HAS_METHOD_OVERRIDE
108  #endif
109  #if __has_feature(cxx_defaulted_functions) && __has_feature(cxx_deleted_functions)
110  #define DISTI_HAS_SPECIAL_MEM_FUN_DEL
111  #endif
112  #if __has_feature(cxx_static_assert)
113  #define DISTI_HAS_STATIC_ASSERT
114  #endif
115 
116  // This actually depends on which standard library is in use, but it's a safe bet.
117  #define DISTI_HAS_TYPE_TRAITS
118 #endif
119 
120 ///////////////////////////////////////////////////////////////////////////////////////////////////
121 // Shortcut for unrecognized compilers
122 ///////////////////////////////////////////////////////////////////////////////////////////////////
123 #ifdef DISTI_HAS_CPP11 // A single switch to enable everything since compiler is highly compliant
124  // These macros can help with cross-platform portability
125  #define DISTI_IF_HAS_CPP11( x ) x
126  #define DISTI_IF_HAS_CPP11_ELSE( x, y ) x
127 
128  #define DISTI_HAS_RVAL_REFS
129  #define DISTI_HAS_METHOD_OVERRIDE
130  #define DISTI_HAS_SPECIAL_MEM_FUN_DEL
131  #define DISTI_HAS_TYPE_TRAITS
132  #define DISTI_HAS_STATIC_ASSERT
133 #else // Not fully C++11; some features may be enabled piecemeal
134  // These macros can help with cross-platform portability
135  #define DISTI_IF_HAS_CPP11( x )
136  #define DISTI_IF_HAS_CPP11_ELSE( x, y ) y
137 #endif
138 
139 ///////////////////////////////////////////////////////////////////////////////////////////////////
140 // Individual C++11 features. See comment above on DISTI_NO_* vs. DISTI_HAS_* macros.
141 ///////////////////////////////////////////////////////////////////////////////////////////////////
142 #if !defined( DISTI_NO_RVAL_REFS ) && defined( DISTI_HAS_RVAL_REFS )
143  #include <utility>
144  #define DISTI_RVAL_MOVE(x) std::move(x)
145  #define DISTI_IF_HAS_RVAL_REFS_ELSE( x, y ) x
146 #else
147  #undef DISTI_HAS_RVAL_REFS
148  #define DISTI_RVAL_MOVE(x) (x)
149  #define DISTI_IF_HAS_RVAL_REFS_ELSE( x, y ) y
150 #endif
151 
152 ///////////////////////////////////////////////////////////////////////////////////////////////////
153 #if !defined( DISTI_NO_METHOD_OVERRIDE ) && defined( DISTI_HAS_METHOD_OVERRIDE )
154  // Add this to the end of an overridden method
155  #define DISTI_METHOD_OVERRIDE override
156  // Add this to the end of a method that should not be overridden
157  #define DISTI_METHOD_FINAL final
158 #else
159  #undef DISTI_HAS_METHOD_OVERRIDE
160  #define DISTI_METHOD_OVERRIDE
161  #define DISTI_METHOD_FINAL
162 #endif
163 
164 ///////////////////////////////////////////////////////////////////////////////////////////////////
165 #if !defined( DISTI_NO_SPECIAL_MEM_FUN_DEL ) && defined( DISTI_HAS_SPECIAL_MEM_FUN_DEL )
166  // Add these to the end of special member functions to delete them.
167  #define DISTI_SPECIAL_MEM_FUN_DELETE = delete
168 #else
169  #undef DISTI_HAS_SPECIAL_MEM_FUN_DEL
170  #define DISTI_SPECIAL_MEM_FUN_DELETE
171 #endif
172 
173 ///////////////////////////////////////////////////////////////////////////////////////////////////
174 #if !defined( DISTI_NO_TYPE_TRAITS ) && defined( DISTI_HAS_TYPE_TRAITS )
175  // Use this by including <type_traits> and then providing a default, e.g.,
176  // DISTI_IF_HAS_TYPE_TRAITS_ELSE( std::is_const<T>::value, false )
177  #define DISTI_IF_HAS_TYPE_TRAITS_ELSE( x, y ) x
178 #else
179  #undef DISTI_HAS_TYPE_TRAITS
180  #define DISTI_IF_HAS_TYPE_TRAITS_ELSE( x, y ) y
181 
182  namespace disti
183  {
184  // The _cppLangSupportDetail namespace is here to hide implementation details, mostly for things
185  // that are standard but not available on all supported platforms.
186  namespace _cppLangSupportDetail
187  {
188  /// Replacement for std::is_convertible, adapted from Loki 0.1.7.
189  /////////////////////////////////////////////////////////////////////////////////
190  /// \copyright The Loki Library, Copyright (c) 2001 by Andrei Alexandrescu<br />
191  /// This code accompanies the book:
192  /// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
193  /// Patterns Applied". Copyright (c) 2001. Addison-Wesley.<br />
194  /// Permission to use, copy, modify, distribute and sell this software for any
195  /// purpose is hereby granted without fee, provided that the above copyright
196  /// notice appear in all copies and that both that copyright notice and this
197  /// permission notice appear in supporting documentation.<br />
198  /// The author or Addison-Welsey Longman make no representations about the
199  /// suitability of this software for any purpose. It is provided "as is"
200  /// without express or implied warranty.<br />
201  /////////////////////////////////////////////////////////////////////////////////
202  template <class T, class U>
204  {
205  private:
206  typedef char Small;
207  struct Big { char dummy[2]; };
208  static Big Test(...);
209  static Small Test(U);
210  static T MakeT();
211  public:
212  enum { value = sizeof(Small) == sizeof((Test(MakeT()))) };
213  };
214 
215  template <class T> struct is_convertible<T, T > { enum { value = true }; }; //< Replacement for std::is_convertible, adapted from Loki 0.1.7.
216  template <class T> struct is_convertible<void, T > { enum { value = false }; }; //< Replacement for std::is_convertible, adapted from Loki 0.1.7.
217  template <class T> struct is_convertible<T, void> { enum { value = false }; }; //< Replacement for std::is_convertible, adapted from Loki 0.1.7.
218  template<> struct is_convertible<void, void> { enum { value = true }; }; //< Replacement for std::is_convertible, adapted from Loki 0.1.7.
219  }
220  }
221 #endif
222 
223 ///////////////////////////////////////////////////////////////////////////////////////////////////
224 #if defined( DISTI_NO_STATIC_ASSERT )
225  #undef DISTI_HAS_STATIC_ASSERT
226  #define DISTI_STATIC_ASSERT( expr, msg )
227 #else
228  #define DISTI_PREPROC_STRINGIFY_HELPER(s) #s
229  #define DISTI_PREPROC_STRINGIFY(s) DISTI_PREPROC_STRINGIFY_HELPER(s)
230 
231  #if defined( DISTI_HAS_STATIC_ASSERT )
232  /// \brief Uses C++11's static_assert() because it is available on this platform.
233  /// \param expr a compile-time integral or pointer expression
234  /// \param msg a C identifier that will appear in compiler diagnostics
235  /// \note For older compilers' benefit, \a msg should be a C identifier such as:
236  /// \code{.cpp}
237  /// DISTI_STATIC_ASSERT( (std::is_convertible<T*,ConvertsTo*>::value), class_does_not_inherit_from_##ConvertsTo )
238  /// \endcode
239  /// which shows a compile-time error that typically includes: "ERROR_class_does_not_inherit_from_Group".
240  /// If it is not a C identifier, you may get spurious error messages at compile time compilers without static_assert.
241  #define DISTI_STATIC_ASSERT( expr, msg ) static_assert( expr, DISTI_PREPROC_STRINGIFY(msg) )
242  #else
243  namespace disti
244  {
245  namespace _cppLangSupportDetail
246  {
247  // Helpers for DISTI_STATIC_ASSERT
248  // \note Adapted from Loki 0.1.7.
249  template<int> struct CompileTimeError;
250  template<> struct CompileTimeError<true> { CompileTimeError() {} };
251  }
252  }
253 
254  /// \brief Poor man's version of C++11's static_assert()
255  /// \param expr a compile-time integral or pointer expression
256  /// \param msg a C identifier that will appear in compiler diagnostics
257  /// \note For older compilers' benefit, \a msg should be a C identifier such as:
258  /// \code{.cpp}
259  /// DISTI_STATIC_ASSERT( (std::is_convertible<T*,ConvertsTo*>::value), class_does_not_inherit_from_##ConvertsTo )
260  /// \endcode
261  /// which shows a compile-time error that typically includes: "ERROR_class_does_not_inherit_from_Group".
262  /// If it is not a C identifier, you may get spurious error messages at compile time compilers without static_assert.
263  /// \note Adapted from Loki 0.1.7.
264  #define DISTI_STATIC_ASSERT(expr, msg) \
265  { \
266  ::disti::_cppLangSupportDetail::CompileTimeError<((expr) != 0)> ERROR_##msg; \
267  (void) ERROR_##msg; \
268  }
269  #endif
270 #endif
271 
272 ////////////////////////////////////////////////////////////////////////////////
273 /// Convenience macro to check that one type converts to another at compile-time.
274 /// \param T A class to check
275 /// \param ConvertsTo A class to test T* against to verify that it can be
276 /// converted to ConvertsTo* without a cast.
277 /// \note This macro appears here for grouping with like code, but macros
278 /// aren't scoped to namespace.
279 ////////////////////////////////////////////////////////////////////////////////
280 #ifdef DISTI_HAS_TYPE_TRAITS
281  #define DISTI_STATIC_ASSERT_IS_CONVERTIBLE_TO( T, ConvertsTo ) DISTI_STATIC_ASSERT( (std::is_convertible<T*,ConvertsTo*>::value), class_does_not_inherit_from_##ConvertsTo );
282 #else
283  #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 )
284 #endif
285 
286 #endif
Replacement for std::is_convertible, adapted from Loki 0.1.7.
Definition: gls_cpp_lang_support.h:203
Definition: gls_cpp_lang_support.h:249
Definition: bmpimage.h:46