// bsls_keyword.h -*-C++-*- #ifndef INCLUDED_BSLS_KEYWORD #define INCLUDED_BSLS_KEYWORD #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide macros for forward language dialect compatibility. // //@CLASSES: // //@MACROS: // BSLS_KEYWORD_CONSTEXPR: C++11 'constexpr' keyword // BSLS_KEYWORD_CONSTEXPR_MEMBER: for 'static constexpr' data members // BSLS_KEYWORD_CONSTEXPR_RELAXED: C++14 'constexpr' keyword (Deprecated) // BSLS_KEYWORD_CONSTEXPR_CPP14: C++14 'constexpr' keyword // BSLS_KEYWORD_CONSTEXPR_CPP17: C++17 'constexpr' keyword // BSLS_KEYWORD_DELETED: C++11 '= delete' function definition // BSLS_KEYWORD_EXPLICIT: C++11 'explicit' for conversion operators // BSLS_KEYWORD_FINAL: C++11 'final' keyword // BSLS_KEYWORD_INLINE_CONSTEXPR: Combination macro for 'inline constexpr' // BSLS_KEYWORD_INLINE_VARIABLE: C++17 'inline' keyword for variables // BSLS_KEYWORD_NOEXCEPT: C++11 'noexcept' keyword // BSLS_KEYWORD_NOEXCEPT_AVAILABLE: 'C++11' 'noexcept' flag // BSLS_KEYWORD_NOEXCEPT_OPERATOR(expr): C++11 'noexcept' operation // BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(...): C++11 noexcept function qualifier // BSLS_KEYWORD_OVERRIDE: C++11 'override' keyword // //@DESCRIPTION: This component provides a suite of macros that simplify the use // of language keywords that may not exist in all supported dialects of the C++ // language. For example, 'BSLS_KEYWORD_NOEXCEPT' is replaced with 'noexcept' // on compilers supporting at least the C++11 language standard, and replaced // with nothing on compilers supporting an older (e.g., C++03) standard. The // goal is to allow implementation of components such that they can take // advantage of some C++11 or later features when compiled with C++11 or later // mode enabled while also correctly compiling in C++03 mode. The // functionality of the respective features won't be available in C++03 mode. // ///Macro Summary ///------------- // The following are the macros provided by this component. // //: 'BSLS_KEYWORD_CONSTEXPR': //: This macro inserts the keyword 'constexpr' when compiling with C++11 //: or later mode and inserts nothing when compiling with C++03 mode. //: //: 'BSLS_KEYWORD_CONSTEXPR_MEMBER': //: This macro inserts the keyword 'constexpr' when compiling with C++11 //: or later mode and inserts the keyword 'const' when compiling with C++03 //: mode. This macro is intended to support declaring static data members. //: //: 'BSLS_KEYWORD_CONSTEXPR_RELAXED': //: !DEPRECATED! Use 'BSLS_KEYWORD_CONSTEXPR_CPP14' instead. This macro //: inserts the keyword 'constexpr' when compiling with C++14 or later mode //: and inserts nothing when compiling with C++03/C++11 mode. //: //: 'BSLS_KEYWORD_CONSTEXPR_CPP14': //: This macro inserts the keyword 'constexpr' when compiling with C++14 //: or later mode and inserts nothing when compiling with C++03/C++11 mode. //: See Example 2 below for a better description of the differences between //: 'constexpr' between C++11, C++14, and C++17. //: //: 'BSLS_KEYWORD_CONSTEXPR_CPP17': //: This macro inserts the keyword 'constexpr' when compiling with C++17 //: or later mode and inserts nothing when compiling with C++03/C++11/C++14 //: mode. See Example 2 below for a better description of the differences //: between 'constexpr' between C++11, C++14, and C++17. //: //: 'BSLS_KEYWORD_DELETED': //: This macro inserts the text '= delete' when compiling with C++11 //: or later mode and inserts nothing when compiling with C++03 mode. //: //: 'BSLS_KEYWORD_EXPLICIT': //: This macro inserts the keyword 'explicit' when compiling with C++11 //: or later mode and inserts nothing when compiling with C++03 mode. //: //: 'BSLS_KEYWORD_FINAL': //: This macro inserts the keyword 'final' when compiling with C++11 or //: later mode and inserts nothing when compiling with C++03 mode. //: //: 'BSLS_KEYWORD_INLINE_CONSTEXPR' //: This macro inserts the keywords 'inline constexpr' when compiling with //: C++17 or later mode and inserts the best approximation in earlier //: dialects, ultimately degrading down to 'static const' in C++03. //: //: 'BSLS_KEYWORD_INLINE_VARIABLE' //: This macro inserts the keyword 'inline' when compiling with C++17 or //: later mode and inserts nothing when compiling with C++03/C++11/C++14 //: mode. //: //: 'BSLS_KEYWORD_NOEXCEPT': //: This macro inserts the keyword 'noexcept' when compiling with C++11 //: or later mode and inserts nothing when compiling with C++03 mode. //: //: 'BSLS_KEYWORD_NOEXCEPT_AVAILABLE': //: This macro expands to 'true' when the 'noexcept' feature is available //: and 'false' otherwise. //: //: 'BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(BOOL_EXPRESSION)': //: This macro inserts the exception specification //: 'noexcept(BOOL_EXPRESSION)' when compiling with C++11 or later mode and //: inserts nothing when compiling with C++03 mode. This macro is used to //: specify which version of noexcept is intended when multiple 'noexcept's //: are used in a single statement. //: //: 'BSLS_KEYWORD_NOEXCEPT_OPERATOR(expr)': //: This macro inserts the operation 'noexcept(expr)' when compiling with //: C++11 or later mode and inserts the literal 'false' when compiling with //: C++03 mode. //: //: 'BSLS_KEYWORD_OVERRIDE' //: This macro inserts the keyword 'override' when compiling with C++11 //: or later mode and inserts nothing when compiling with C++03 mode. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Preparing C++03 Code for C++11 Features /// - - - - - - - - - - - - - - - - - - - - - - - - - // To use these macros, simply insert them where the corresponding C++11 // keyword would go. When compiling with C++03 mode there will be no effect // but when compiling with C++11 mode additional restrictions will apply. When // compiling with C++11 mode the restriction will be checked providing some // additional checking over what is done with C++11. // // C++ uses the 'explicit' keyword to indicate that constructors taking just // one argument are not considered for implicit conversions. Instead, they can // only be used for explicit conversions. C++ also provides the ability to // define conversion operators but prior to C++11 these conversion operators // are considered for implicit conversion. C++11 allows the use of the // 'explicit' keyword with conversion operators to avoid its use for implicit // conversions. The macro 'BSLS_KEYWORD_EXPLICIT' can be used to mark // conversions as explicit conversions which will be checked when compiling // with C++11 mode. For example, an 'Optional' type may have an explicit // conversion to 'bool' to indicate that the value is set (note the conversion // operator): //.. // template <class TYPE> // class Optional // { // TYPE* d_value_p; // public: // Optional(): d_value_p() {} // explicit Optional(const TYPE& value): d_value_p(new TYPE(value)) {} // ~Optional() { delete d_value_p; } // // ... // // BSLS_KEYWORD_EXPLICIT operator bool() const { return d_value_p; } // }; //.. // When using an object of the 'Optional' class in a condition it is desirable // that it converts to a 'bool': //.. // void testFunction() { // Optional<int> value; // if (value) { /*... */ } //.. // In places where an implicit conversion takes place it is not desirable that // the conversion is used. When compiling with C++11 mode the conversion // operator will not be used, e.g., the following code will result in an error: //.. // #if BSLS_COMPILERFEATURES_CPLUSPLUS < 201103L // bool flag = value; // #endif // } //.. // The code will compile successfully when using C++03 mode; without the macro, // when using C++11 or greater mode we get an error like this: //.. // error: cannot convert 'Optional<int>' to 'bool' in initialization //.. // // When defining conversion operators to 'bool' for code which needs to compile // with C++03 mode the conversion operator should convert to a member pointer // type instead: doing so has a similar effect to making the conversion // operator 'explicit'. // // Some classes are not intended for use as a base class. To clearly label // these classes and enforce that they can't be derived from C++11 allows using // the 'final' keyword after the class name in the class definition to label // classes which are not intended to be derived from. The macro // 'BSLS_KEYWORD_FINAL' is replaced by 'final' when compiling with C++11 // causing the compiler to enforce that a class can't be further derived. The // code below defines a class which can't be derived from: //.. // class FinalClass BSLS_KEYWORD_FINAL // { // int d_value; // public: // explicit FinalClass(int value = 0): d_value(value) {} // int value() const { return d_value; } // }; //.. // An attempt to derive from this class will fail when compiling with C++11 // mode: //.. // #if BSLS_COMPILERFEATURES_CPLUSPLUS < 201103L // class FinalClassDerived : public FinalClass { // int d_anotherValue; // public: // explicit FinalClassDerived(int value) // : d_anotherValue(2 * value) { // } // int anotherValue() const { return d_anotherValue; } // }; // #endif //.. // The code will compile successfully when using C++03 mode; without the macro, // when using C++11 or greater mode we get an error like this: //.. // error: cannot derive from 'final' base 'FinalClass' in derived type // 'FinalClassDerived' //.. // // Sometime it is useful to declare that an overriding function is the final // overriding function and further derived classes won't be allowed to further // override the function. One use of this feature could be informing the // compiler that it won't need to use virtual dispatch when calling this // function on a pointer or a reference of the corresponding type. C++11 // allows marking functions as the final overrider using the keyword 'final'. // The macro 'BSLS_KEYWORD_FINAL' can also be used for this purpose. To // demonstrate the use of this keyword first a base class with a 'virtual' // function is defined: //.. // struct FinalFunctionBase // { // virtual int f() { return 0; } // }; //.. // When defining a derived class this function 'f' can be marked as the final // overrider using 'BSLS_KEYWORD_FINAL': //.. // struct FinalFunctionDerived: FinalFunctionBase // { // int f() BSLS_KEYWORD_FINAL { return 1; } // }; //.. // The semantics of the overriding function aren't changed but a further // derived class can't override the function 'f', i.e., the following code will // result in an error when compiling with C++11 mode: //.. // #if BSLS_COMPILERFEATURES_CPLUSPLUS < 201103L // struct FinalFunctionFailure: FinalFunctionDerived // { // int f() { return 2; } // }; // #endif //.. // The code will compile successfully when using C++03 mode; without the macro, // when using C++11 or greater mode we get an error like this: //.. // error: virtual function 'virtual int FinalFunctionFailure::f()' // error: overriding final function 'virtual int FinalFunctionDerived::f()' //.. // // The C++11 keyword 'override' is used to identify functions overriding a // 'virtual' function from a base class. If a function identified as // 'override' does not override a 'virtual' function from a base class the // compilation results in an error. The macro 'BSLS_KEYWORD_OVERRIDE' is used // to insert the 'override' keyword when compiling with C++11 mode. When // compiling with C++03 mode it has no effect but it both cases it documents // that a function is overriding a 'virtual' function from a base class. To // demonstrate the use of the 'BSLS_KEYWORD_OVERRIDE' macro first a base class // is defined: //.. // struct OverrideBase // { // virtual int f() const { return 0; } // }; //.. // When overriding 'OverrideBase::f' in a derived class the // 'BSLS_KEYWORD_OVERRIDE' macro should be used to ascertain that the function // in the derived class is indeed overriding a 'virtual' function: //.. // struct OverrideSuccess: OverrideBase // { // int f() const BSLS_KEYWORD_OVERRIDE { return 1; } // }; //.. // The above code compiles successfully with both C++03 mode and C++11. When // the function meant to be an override actually isn't overriding any function // the compilation will fail when using C++11 mode as is demonstrated by the // following example (note the missing 'const' in the function declaration): //.. // #if BSLS_COMPILERFEATURES_CPLUSPLUS < 201103L // struct OverrideFailure: OverrideBase // { // int f() BSLS_KEYWORD_OVERRIDE { return 2; } // }; // #endif //.. // The code will compile successfully when using C++03 mode (though it might // produce a warning); without the macro, when using C++11 or greater mode we // get an error like this: //.. // error: 'int OverrideFailure::f()' marked 'override', but does not // override //.. // ///Example 2: Creating an extended 'constexpr' function /// - - - - - - - - - - - - - - - - - - - - - - - - - - // To use these macros, simply insert them where the corresponding C++14 // keyword would go. When compiling with C++03 or C++11 mode there will be no // effect but when compiling with C++14 mode additional restrictions will // apply. When compiling with C++14 mode the restriction will be checked // providing some additional checking over what is done with C++11 or C++03. // // C++11 uses the 'constexpr' keyword to indicate that a (very simple) function // may be evaluated compile-time if all its input is known compile time. C++14 // allows more complex functions to be 'constexpr'. Also, in C++14, // 'constexpr' member functions are not implicitly 'const' as in C++11. // Thefore we have a separate macro 'BSLS_KEYWORD_CONSTEXPR_CPP14' that can be // used to mark functions 'constexpr' when compiling with C++14 mode: //.. // BSLS_KEYWORD_CONSTEXPR_CPP14 // int complexConstexprFunc(bool b) // { // if (b) { // return 42; // RETURN // } // else { // return 17; // RETURN // } // } //.. // When compiling with C++14 'constexpr' support it is possible to use the // result of 'complexConstexprFunc' in compile-time constants: //.. // void useComplexConstexprFunc() // { // #ifdef BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP14 // constexpr // #endif // int result = complexConstexprFunc(true); // ASSERT(42 == result); //.. // The macro 'BSLS_KEYWORD_CONSTEXPR_CPP14' can also be used on variables to // achieve an identical result: //.. // BSLS_KEYWORD_CONSTEXPR_CPP14 int result2 = complexConstexprFunc(true); // ASSERT(42 == result2); // } //.. // C++17 made small but significant changes to what is allowed in a 'constexpr' // function. Notably, a lambda can now be defined in such a function (and, if // not called at compile time, does not itself need to be 'constexpr'). To // take advantage of this there is a separate macro // 'BSLS_KEYWORD_CONSTEXPR_CPP17' that can be used to mark functions // 'constexpr' when compiling with C++17 mode: //.. // BSLS_KEYWORD_CONSTEXPR_CPP17 // int moreComplexConstexprFunc(bool b) // { // if (b) { // return 42; // RETURN // } // else { // #if BSLS_COMPILERFEATURES_CPLUSPLUS >= 201103L // return []{ // static int b = 17; // return b; // }(); // RETURN // #else // return 17; // #endif // } // } //.. // Then, just like 'useComplexConstexprFunc', we can invoke // 'moreComplexConstexprFunc' to populate a compile-time constant when it is // supported: //.. // void useMoreComplexConstexprFunc() // { // BSLS_KEYWORD_CONSTEXPR_CPP17 int result // = moreComplexConstexprFunc(true); // ASSERT(42 == result); // } //.. #include <bsls_compilerfeatures.h> #ifdef BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR # define BSLS_KEYWORD_CONSTEXPR constexpr # define BSLS_KEYWORD_CONSTEXPR_MEMBER constexpr #else # define BSLS_KEYWORD_CONSTEXPR # define BSLS_KEYWORD_CONSTEXPR_MEMBER const #endif #ifdef BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP14 # define BSLS_KEYWORD_CONSTEXPR_CPP14 constexpr #else # define BSLS_KEYWORD_CONSTEXPR_CPP14 #endif # define BSLS_KEYWORD_CONSTEXPR_RELAXED BSLS_KEYWORD_CONSTEXPR_CPP14 #ifdef BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP17 # define BSLS_KEYWORD_CONSTEXPR_CPP17 constexpr #else # define BSLS_KEYWORD_CONSTEXPR_CPP17 #endif #ifdef BSLS_COMPILERFEATURES_SUPPORT_DELETED_FUNCTIONS # define BSLS_KEYWORD_DELETED = delete #else # define BSLS_KEYWORD_DELETED #endif #ifdef BSLS_COMPILERFEATURES_SUPPORT_INLINE_CONSTEXPR # define BSLS_KEYWORD_INLINE_CONSTEXPR inline constexpr #elif defined(BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR) # define BSLS_KEYWORD_INLINE_CONSTEXPR constexpr #else # define BSLS_KEYWORD_INLINE_CONSTEXPR static const #endif #ifdef BSLS_COMPILERFEATURES_SUPPORT_INLINE_VARIABLES # define BSLS_KEYWORD_INLINE_VARIABLE inline #else # define BSLS_KEYWORD_INLINE_VARIABLE #endif #ifdef BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT # define BSLS_KEYWORD_NOEXCEPT noexcept # define BSLS_KEYWORD_NOEXCEPT_AVAILABLE true # define BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(...) noexcept(__VA_ARGS__) # define BSLS_KEYWORD_NOEXCEPT_OPERATOR(...) noexcept(__VA_ARGS__) #else # define BSLS_KEYWORD_NOEXCEPT # define BSLS_KEYWORD_NOEXCEPT_AVAILABLE false # define BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(...) # define BSLS_KEYWORD_NOEXCEPT_OPERATOR(...) false #endif #ifdef BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT # define BSLS_KEYWORD_EXPLICIT explicit #else # define BSLS_KEYWORD_EXPLICIT #endif #ifdef BSLS_COMPILERFEATURES_SUPPORT_FINAL # define BSLS_KEYWORD_FINAL final #else # define BSLS_KEYWORD_FINAL #endif #ifdef BSLS_COMPILERFEATURES_SUPPORT_OVERRIDE # define BSLS_KEYWORD_OVERRIDE override #else # define BSLS_KEYWORD_OVERRIDE #endif // ---------------------------------------------------------------------------- #endif // ---------------------------------------------------------------------------- // Copyright 2018 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------