From e9a53f2e69b9a74bfa0445907fb87d87beb624d4 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 1 Sep 2013 16:31:16 +0000 Subject: [PATCH] Extracted BOOST_EXPLICIT_OPERATOR_BOOL macro from Boost.Log. [SVN r85543] --- doc/explicit_operator_bool.qbk | 68 ++++++++++ .../boost/utility/explicit_operator_bool.hpp | 128 ++++++++++++++++++ test/explicit_operator_bool.cpp | 54 ++++++++ ...it_operator_bool_compile_fail_conv_int.cpp | 40 ++++++ ..._operator_bool_compile_fail_conv_pvoid.cpp | 40 ++++++ ...icit_operator_bool_compile_fail_delete.cpp | 40 ++++++ ...licit_operator_bool_compile_fail_shift.cpp | 40 ++++++ 7 files changed, 410 insertions(+) create mode 100644 doc/explicit_operator_bool.qbk create mode 100644 include/boost/utility/explicit_operator_bool.hpp create mode 100644 test/explicit_operator_bool.cpp create mode 100644 test/explicit_operator_bool_compile_fail_conv_int.cpp create mode 100644 test/explicit_operator_bool_compile_fail_conv_pvoid.cpp create mode 100644 test/explicit_operator_bool_compile_fail_delete.cpp create mode 100644 test/explicit_operator_bool_compile_fail_shift.cpp diff --git a/doc/explicit_operator_bool.qbk b/doc/explicit_operator_bool.qbk new file mode 100644 index 0000000..4a7e4b1 --- /dev/null +++ b/doc/explicit_operator_bool.qbk @@ -0,0 +1,68 @@ +[/ + / Copyright (c) 2013 Andrey Semashev + / + / Distributed under the Boost Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + /] + +[article BOOST_EXPLICIT_OPERATOR_BOOL and BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL + [quickbook 1.5] + [authors [Semashev, Andrey]] + [copyright 2013 Andrey Semashev] + [license + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + [@http://www.boost.org/LICENSE_1_0.txt]) + ] +] + +[/===============] +[section Overview] +[/===============] + +`BOOST_EXPLICIT_OPERATOR_BOOL()` and `BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL()` are compatibility helper macros that expand to an explicit conversion operator to `bool`. For compilers not supporting explicit conversion operators introduced in C++11 the macros expand to a conversion operator that implements the [@http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool safe bool idiom]. In case if the compiler is not able to handle safe bool idiom well the macros expand to a regular conversion operator to `bool`. + +[endsect] + + +[/===============] +[section Examples] +[/===============] + +Both macros are intended to be placed within a user's class definition. The generated conversion operators will be implemented in terms of `operator!()` that should be defined by user in this class. In case of `BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL()` the generated conversion operator will be declared `constexpr` which requires the corresponding `operator!()` to also be `constexpr`. + + template< typename T > + class my_ptr + { + T* m_p; + + public: + BOOST_EXPLICIT_OPERATOR_BOOL() + + bool operator!() const + { + return !m_p; + } + }; + +Now `my_ptr` can be used in conditional expressions, similarly to a regular pointer: + + my_ptr< int > p; + if (p) + std::cout << "true" << std::endl; + +[endsect] + +[/===============] +[section History] +[/===============] + +[heading boost 1.55] + +* The macro was extracted from Boost.Log. + +[endsect] + + + + diff --git a/include/boost/utility/explicit_operator_bool.hpp b/include/boost/utility/explicit_operator_bool.hpp new file mode 100644 index 0000000..8843e0c --- /dev/null +++ b/include/boost/utility/explicit_operator_bool.hpp @@ -0,0 +1,128 @@ +/* + * Copyright Andrey Semashev 2007 - 2013. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file explicit_operator_bool.hpp + * \author Andrey Semashev + * \date 08.03.2009 + * + * This header defines a compatibility macro that implements an unspecified + * \c bool operator idiom, which is superseded with explicit conversion operators in + * C++11. + */ + +#ifndef BOOST_UTILITY_EXPLICIT_OPERATOR_BOOL_HPP_INCLUDED_ +#define BOOST_UTILITY_EXPLICIT_OPERATOR_BOOL_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + +/*! + * \brief The macro defines an explicit operator of conversion to \c bool + * + * The macro should be used inside the definition of a class that has to + * support the conversion. The class should also implement operator!, + * in terms of which the conversion operator will be implemented. + */ +#define BOOST_EXPLICIT_OPERATOR_BOOL()\ + BOOST_FORCEINLINE explicit operator bool () const\ + {\ + return !this->operator! ();\ + } + +/*! + * \brief The macro defines a constexpr explicit operator of conversion to \c bool + * + * The macro should be used inside the definition of a class that has to + * support the conversion. The class should also implement operator!, + * in terms of which the conversion operator will be implemented. + */ +#define BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL()\ + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit operator bool () const\ + {\ + return !this->operator! ();\ + } + +#else // !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + +#if (defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530)) && !defined(BOOST_NO_COMPILER_CONFIG) +// Sun C++ 5.3 can't handle the safe_bool idiom, so don't use it +#define BOOST_NO_UNSPECIFIED_BOOL +#endif // (defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530)) && !defined(BOOST_NO_COMPILER_CONFIG) + +#if !defined(BOOST_NO_UNSPECIFIED_BOOL) + +namespace boost { + +namespace detail { + +#if !defined(_MSC_VER) + + struct unspecified_bool + { + // NOTE TO THE USER: If you see this in error messages then you tried + // to apply an unsupported operator on the object that supports + // explicit conversion to bool. + struct OPERATORS_NOT_ALLOWED; + static void true_value(OPERATORS_NOT_ALLOWED*) {} + }; + typedef void (*unspecified_bool_type)(unspecified_bool::OPERATORS_NOT_ALLOWED*); + +#else + + // MSVC is too eager to convert pointer to function to void* even though it shouldn't + struct unspecified_bool + { + // NOTE TO THE USER: If you see this in error messages then you tried + // to apply an unsupported operator on the object that supports + // explicit conversion to bool. + struct OPERATORS_NOT_ALLOWED; + void true_value(OPERATORS_NOT_ALLOWED*) {} + }; + typedef void (unspecified_bool::*unspecified_bool_type)(unspecified_bool::OPERATORS_NOT_ALLOWED*); + +#endif + +} // namespace detail + +} // namespace boost + +#define BOOST_EXPLICIT_OPERATOR_BOOL()\ + BOOST_FORCEINLINE operator boost::detail::unspecified_bool_type () const\ + {\ + return (!this->operator! () ? &boost::detail::unspecified_bool::true_value : (boost::detail::unspecified_bool_type)0);\ + } + +#define BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL()\ + BOOST_FORCEINLINE BOOST_CONSTEXPR operator boost::detail::unspecified_bool_type () const\ + {\ + return (!this->operator! () ? &boost::detail::unspecified_bool::true_value : (boost::detail::unspecified_bool_type)0);\ + } + +#else // !defined(BOOST_NO_UNSPECIFIED_BOOL) + +#define BOOST_EXPLICIT_OPERATOR_BOOL()\ + BOOST_FORCEINLINE operator bool () const\ + {\ + return !this->operator! ();\ + } + +#define BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL()\ + BOOST_FORCEINLINE BOOST_CONSTEXPR operator bool () const\ + {\ + return !this->operator! ();\ + } + +#endif // !defined(BOOST_NO_UNSPECIFIED_BOOL) + +#endif // !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + +#endif // BOOST_UTILITY_EXPLICIT_OPERATOR_BOOL_HPP_INCLUDED_ diff --git a/test/explicit_operator_bool.cpp b/test/explicit_operator_bool.cpp new file mode 100644 index 0000000..07dd01b --- /dev/null +++ b/test/explicit_operator_bool.cpp @@ -0,0 +1,54 @@ +/* + * Copyright Andrey Semashev 2007 - 2013. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file explicit_operator_bool_compile.cpp + * \author Andrey Semashev + * \date 17.07.2010 + * + * \brief This test checks that explicit operator bool can be used in + * the valid contexts. + */ + +#define BOOST_TEST_MODULE explicit_operator_bool_compile + +#include + +namespace { + + // A test object that has the operator of explicit conversion to bool + struct checkable1 + { + BOOST_EXPLICIT_OPERATOR_BOOL() + bool operator! () const + { + return false; + } + }; + + struct checkable2 + { + BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL() + BOOST_CONSTEXPR bool operator! () const + { + return false; + } + }; + +} // namespace + +int main(int, char*[]) +{ + checkable1 val1; + if (val1) + { + checkable2 val2; + if (val2) + return 0; + } + + return 1; +} diff --git a/test/explicit_operator_bool_compile_fail_conv_int.cpp b/test/explicit_operator_bool_compile_fail_conv_int.cpp new file mode 100644 index 0000000..384f2ab --- /dev/null +++ b/test/explicit_operator_bool_compile_fail_conv_int.cpp @@ -0,0 +1,40 @@ +/* + * Copyright Andrey Semashev 2007 - 2013. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file explicit_operator_bool_compile_fail_conv_int.cpp + * \author Andrey Semashev + * \date 17.07.2010 + * + * \brief This test checks that explicit operator bool cannot be used in + * an unintended context. + */ + +#define BOOST_TEST_MODULE explicit_operator_bool_compile_fail_conv_int + +#include + +namespace { + + // A test object that has the operator of explicit conversion to bool + struct checkable + { + BOOST_EXPLICIT_OPERATOR_BOOL() + bool operator! () const + { + return false; + } + }; + +} // namespace + +int main(int, char*[]) +{ + checkable val; + int n = val; + + return 0; +} diff --git a/test/explicit_operator_bool_compile_fail_conv_pvoid.cpp b/test/explicit_operator_bool_compile_fail_conv_pvoid.cpp new file mode 100644 index 0000000..0c007ba --- /dev/null +++ b/test/explicit_operator_bool_compile_fail_conv_pvoid.cpp @@ -0,0 +1,40 @@ +/* + * Copyright Andrey Semashev 2007 - 2013. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file explicit_operator_bool_compile_fail_conv_pvoid.cpp + * \author Andrey Semashev + * \date 17.07.2010 + * + * \brief This test checks that explicit operator bool cannot be used in + * an unintended context. + */ + +#define BOOST_TEST_MODULE explicit_operator_bool_compile_fail_conv_pvoid + +#include + +namespace { + + // A test object that has the operator of explicit conversion to bool + struct checkable + { + BOOST_EXPLICIT_OPERATOR_BOOL() + bool operator! () const + { + return false; + } + }; + +} // namespace + +int main(int, char*[]) +{ + checkable val; + void* p = val; + + return 0; +} diff --git a/test/explicit_operator_bool_compile_fail_delete.cpp b/test/explicit_operator_bool_compile_fail_delete.cpp new file mode 100644 index 0000000..d780f94 --- /dev/null +++ b/test/explicit_operator_bool_compile_fail_delete.cpp @@ -0,0 +1,40 @@ +/* + * Copyright Andrey Semashev 2007 - 2013. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file explicit_operator_bool_compile_fail_delete.cpp + * \author Andrey Semashev + * \date 17.07.2010 + * + * \brief This test checks that explicit operator bool cannot be used in + * an unintended context. + */ + +#define BOOST_TEST_MODULE util_explicit_operator_bool_delete + +#include + +namespace { + + // A test object that has the operator of explicit conversion to bool + struct checkable + { + BOOST_EXPLICIT_OPERATOR_BOOL() + bool operator! () const + { + return false; + } + }; + +} // namespace + +int main(int, char*[]) +{ + checkable val; + delete val; + + return 0; +} diff --git a/test/explicit_operator_bool_compile_fail_shift.cpp b/test/explicit_operator_bool_compile_fail_shift.cpp new file mode 100644 index 0000000..ce563a6 --- /dev/null +++ b/test/explicit_operator_bool_compile_fail_shift.cpp @@ -0,0 +1,40 @@ +/* + * Copyright Andrey Semashev 2007 - 2013. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file explicit_operator_bool_compile_fail_shift.cpp + * \author Andrey Semashev + * \date 17.07.2010 + * + * \brief This test checks that explicit operator bool cannot be used in + * an unintended context. + */ + +#define BOOST_TEST_MODULE explicit_operator_bool_compile_fail_shift + +#include + +namespace { + + // A test object that has the operator of explicit conversion to bool + struct checkable + { + BOOST_EXPLICIT_OPERATOR_BOOL() + bool operator! () const + { + return false; + } + }; + +} // namespace + +int main(int, char*[]) +{ + checkable val; + val << 2; + + return 0; +}