From be95c9e84fd8f0c9ce6ac41486791563224c6c64 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 9 Oct 2026 19:48:54 +0300 Subject: [PATCH 1/3] Implement constexpr anys --- include/boost/any.hpp | 46 +++++++++++----------- include/boost/any/detail/config.hpp | 12 ++++++ include/boost/any/detail/placeholder.hpp | 4 +- include/boost/any/unique_any.hpp | 50 ++++++++++++------------ test/unique_any/base.cpp | 35 +++++++++++++++++ 5 files changed, 97 insertions(+), 50 deletions(-) diff --git a/include/boost/any.hpp b/include/boost/any.hpp index e77d189..c940449 100644 --- a/include/boost/any.hpp +++ b/include/boost/any.hpp @@ -58,7 +58,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// \throws std::bad_alloc or any exceptions arising from the copy /// constructor of the contained type. template - any(const ValueType & value) + BOOST_ANY_IMPL_CONSTEXPR any(const ValueType & value) : content(new holder< typename std::remove_cv::type>::type >(value)) @@ -77,7 +77,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// \throws May fail with a `std::bad_alloc` /// exception or any exceptions arising from the copy /// constructor of the contained type. - any(const any & other) + BOOST_ANY_IMPL_CONSTEXPR any(const any & other) : content(other.content ? other.content->clone() : 0) { } @@ -87,7 +87,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// /// \post other->empty() is true /// \throws Nothing. - any(any&& other) noexcept + BOOST_ANY_IMPL_CONSTEXPR any(any&& other) noexcept : content(other.content) { other.content = 0; @@ -100,7 +100,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// \throws std::bad_alloc or any exceptions arising from the move or /// copy constructor of the contained type. template - any(ValueType&& value + BOOST_ANY_IMPL_CONSTEXPR any(ValueType&& value , typename std::enable_if::value >::type* = 0 // disable if value has type `any&` , typename std::enable_if::value >::type* = 0) // disable if value has type `const ValueType&&` : content(new holder< typename std::decay::type >(std::forward(value))) @@ -114,7 +114,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// Releases any and all resources used in management of instance. /// /// \throws Nothing. - ~any() noexcept + BOOST_ANY_IMPL_CONSTEXPR ~any() noexcept { delete content; } @@ -125,7 +125,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// /// \returns `*this` /// \throws Nothing. - any & swap(any & rhs) noexcept + BOOST_ANY_IMPL_CONSTEXPR any & swap(any & rhs) noexcept { placeholder* tmp = content; content = rhs.content; @@ -142,7 +142,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// or any exceptions arising from the copy constructor of the /// contained type. Assignment satisfies the strong guarantee /// of exception safety. - any & operator=(const any& rhs) + BOOST_ANY_IMPL_CONSTEXPR any & operator=(const any& rhs) { any(rhs).swap(*this); return *this; @@ -173,7 +173,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// contained type. Assignment satisfies the strong guarantee /// of exception safety. template - any & operator=(ValueType&& rhs) + BOOST_ANY_IMPL_CONSTEXPR any & operator=(ValueType&& rhs) { static_assert( !anys::detail::is_basic_any::type>::value, @@ -187,13 +187,13 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// \returns `true` if instance is empty, otherwise `false`. /// \throws Nothing. - bool empty() const noexcept + BOOST_ANY_IMPL_CONSTEXPR bool empty() const noexcept { return !content; } /// \post this->empty() is true - void clear() noexcept + BOOST_ANY_IMPL_CONSTEXPR void clear() noexcept { any().swap(*this); } @@ -204,7 +204,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// /// Useful for querying against types known either at compile time or /// only at runtime. - const boost::typeindex::type_info& type() const noexcept + BOOST_ANY_IMPL_CONSTEXPR const boost::typeindex::type_info& type() const noexcept { return content ? content->type() : boost::typeindex::type_id().type_info(); } @@ -223,24 +223,24 @@ BOOST_ANY_BEGIN_MODULE_EXPORT { public: // structors - holder(const ValueType & value) + BOOST_ANY_IMPL_CONSTEXPR holder(const ValueType & value) : held(value) { } - holder(ValueType&& value) + BOOST_ANY_IMPL_CONSTEXPR holder(ValueType&& value) : held(static_cast< ValueType&& >(value)) { } public: // queries - const boost::typeindex::type_info& type() const noexcept override + BOOST_ANY_IMPL_CONSTEXPR const boost::typeindex::type_info& type() const noexcept override { return boost::typeindex::type_id().type_info(); } - placeholder * clone() const BOOST_OVERRIDE + BOOST_ANY_IMPL_CONSTEXPR placeholder * clone() const BOOST_OVERRIDE { return new holder(held); } @@ -265,7 +265,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// Exchange of the contents of `lhs` and `rhs`. /// \throws Nothing. - inline void swap(any & lhs, any & rhs) noexcept + BOOST_ANY_IMPL_CONSTEXPR inline void swap(any & lhs, any & rhs) noexcept { lhs.swap(rhs); } @@ -278,7 +278,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT // use typeid() comparison, e.g., when our types may travel across // different shared libraries. template - inline ValueType * unsafe_any_cast(any * operand) noexcept + BOOST_ANY_IMPL_CONSTEXPR inline ValueType * unsafe_any_cast(any * operand) noexcept { return std::addressof( static_cast *>(operand->content)->held @@ -286,7 +286,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT } template - inline const ValueType * unsafe_any_cast(const any * operand) noexcept + BOOST_ANY_IMPL_CONSTEXPR inline const ValueType * unsafe_any_cast(const any * operand) noexcept { return boost::unsafe_any_cast(const_cast(operand)); } @@ -295,7 +295,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// \returns Pointer to a ValueType stored in `operand`, nullptr if /// `operand` does not contain specified `ValueType`. template - ValueType * any_cast(any * operand) noexcept + BOOST_ANY_IMPL_CONSTEXPR ValueType * any_cast(any * operand) noexcept { return operand && operand->type() == boost::typeindex::type_id() ? boost::unsafe_any_cast::type>(operand) @@ -305,7 +305,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// \returns Const pointer to a ValueType stored in `operand`, nullptr if /// `operand` does not contain specified `ValueType`. template - inline const ValueType * any_cast(const any * operand) noexcept + BOOST_ANY_IMPL_CONSTEXPR inline const ValueType * any_cast(const any * operand) noexcept { return boost::any_cast(const_cast(operand)); } @@ -314,7 +314,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// \throws boost::bad_any_cast if `operand` does not contain /// specified ValueType. template - ValueType any_cast(any & operand) + BOOST_ANY_IMPL_CONSTEXPR ValueType any_cast(any & operand) { using nonref = typename std::remove_reference::type; @@ -346,7 +346,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// \throws boost::bad_any_cast if `operand` does not contain /// specified `ValueType`. template - inline ValueType any_cast(const any & operand) + BOOST_ANY_IMPL_CONSTEXPR inline ValueType any_cast(const any & operand) { using nonref = typename std::remove_reference::type; return boost::any_cast(const_cast(operand)); @@ -356,7 +356,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// \throws boost::bad_any_cast if `operand` does not contain /// specified `ValueType`. template - inline ValueType any_cast(any&& operand) + BOOST_ANY_IMPL_CONSTEXPR inline ValueType any_cast(any&& operand) { static_assert( std::is_rvalue_reference::value /*true if ValueType is rvalue or just a value*/ diff --git a/include/boost/any/detail/config.hpp b/include/boost/any/detail/config.hpp index 728ce7f..25bbb6b 100644 --- a/include/boost/any/detail/config.hpp +++ b/include/boost/any/detail/config.hpp @@ -7,6 +7,18 @@ #ifndef BOOST_ANY_ANYS_DETAIL_CONFIG_HPP #define BOOST_ANY_ANYS_DETAIL_CONFIG_HPP +#if defined __has_include +# if __has_include () +# include +# endif +#endif + +#ifdef __cpp_lib_constexpr_new +#define BOOST_ANY_IMPL_CONSTEXPR constexpr +#else +#define BOOST_ANY_IMPL_CONSTEXPR +#endif + #ifdef BOOST_ANY_INTERFACE_UNIT # define BOOST_ANY_BEGIN_MODULE_EXPORT export { # define BOOST_ANY_END_MODULE_EXPORT } diff --git a/include/boost/any/detail/placeholder.hpp b/include/boost/any/detail/placeholder.hpp index 1a5776d..88ae874 100644 --- a/include/boost/any/detail/placeholder.hpp +++ b/include/boost/any/detail/placeholder.hpp @@ -27,8 +27,8 @@ namespace detail { class BOOST_SYMBOL_VISIBLE placeholder { public: - virtual ~placeholder() {} - virtual const boost::typeindex::type_info& type() const noexcept = 0; + BOOST_ANY_IMPL_CONSTEXPR virtual ~placeholder() {} + BOOST_ANY_IMPL_CONSTEXPR virtual const boost::typeindex::type_info& type() const noexcept = 0; }; } // namespace detail diff --git a/include/boost/any/unique_any.hpp b/include/boost/any/unique_any.hpp index 99099fd..34ba70f 100644 --- a/include/boost/any/unique_any.hpp +++ b/include/boost/any/unique_any.hpp @@ -61,7 +61,7 @@ class unique_any { /// /// \post other->has_value() is false. /// \throws Nothing. - unique_any(unique_any&& other) noexcept = default; + BOOST_ANY_IMPL_CONSTEXPR unique_any(unique_any&& other) noexcept = default; /// Forwards `value`, so /// that the content of the new instance has type `std::decay_t` @@ -70,7 +70,7 @@ class unique_any { /// \throws std::bad_alloc or any exceptions arising from the move or /// copy constructor of the contained type. template - unique_any(T&& value, typename std::enable_if::value>::type* = nullptr) + BOOST_ANY_IMPL_CONSTEXPR unique_any(T&& value, typename std::enable_if::value>::type* = nullptr) : content(new holder< typename std::decay::type >(std::forward(value))) { static_assert( @@ -95,7 +95,7 @@ class unique_any { /// \throws Nothing. /// \post `value.empty()` is true. template - unique_any(BoostAny&& value, typename std::enable_if::value>::type* = nullptr) noexcept + BOOST_ANY_IMPL_CONSTEXPR unique_any(BoostAny&& value, typename std::enable_if::value>::type* = nullptr) noexcept { content.reset(value.content); value.content = nullptr; @@ -108,7 +108,7 @@ class unique_any { /// \throws std::bad_alloc or any exceptions arising from the move or /// copy constructor of the contained type. template - explicit unique_any(in_place_type_t, Args&&... args) + BOOST_ANY_IMPL_CONSTEXPR explicit unique_any(in_place_type_t, Args&&... args) : content(new holder::type>(std::forward(args)...)) { } @@ -120,7 +120,7 @@ class unique_any { /// \throws std::bad_alloc or any exceptions arising from the move or /// copy constructor of the contained type. template - explicit unique_any(in_place_type_t, std::initializer_list il, Args&&... args) + BOOST_ANY_IMPL_CONSTEXPR explicit unique_any(in_place_type_t, std::initializer_list il, Args&&... args) : content(new holder::type>(il, std::forward(args)...)) { } @@ -137,7 +137,7 @@ class unique_any { /// /// \post `rhs->empty()` is true /// \throws Nothing. - unique_any & operator=(unique_any&& rhs) noexcept = default; + BOOST_ANY_IMPL_CONSTEXPR unique_any & operator=(unique_any&& rhs) noexcept = default; /// Forwards `rhs`, /// discarding previous content, so that the new content of is @@ -148,7 +148,7 @@ class unique_any { /// contained type. Assignment satisfies the strong guarantee /// of exception safety. template - unique_any & operator=(T&& rhs) + BOOST_ANY_IMPL_CONSTEXPR unique_any & operator=(T&& rhs) { unique_any(std::forward(rhs)).swap(*this); return *this; @@ -162,7 +162,7 @@ class unique_any { /// \throws std::bad_alloc or any exceptions arising from the move or /// copy constructor of the contained type. template - typename std::decay::type& emplace(Args&&... args) { + BOOST_ANY_IMPL_CONSTEXPR typename std::decay::type& emplace(Args&&... args) { auto* raw_ptr = new holder::type>(std::forward(args)...); content = std::unique_ptr(raw_ptr); return raw_ptr->held; @@ -176,14 +176,14 @@ class unique_any { /// \throws std::bad_alloc or any exceptions arising from the move or /// copy constructor of the contained type. template - typename std::decay::type& emplace(std::initializer_list il, Args&&... args) { + BOOST_ANY_IMPL_CONSTEXPR typename std::decay::type& emplace(std::initializer_list il, Args&&... args) { auto* raw_ptr = new holder::type>(il, std::forward(args)...); content = std::unique_ptr(raw_ptr); return raw_ptr->held; } /// \post this->has_value() is false. - void reset() noexcept + BOOST_ANY_IMPL_CONSTEXPR void reset() noexcept { content.reset(); } @@ -192,14 +192,14 @@ class unique_any { /// /// \returns `*this` /// \throws Nothing. - void swap(unique_any& rhs) noexcept + BOOST_ANY_IMPL_CONSTEXPR void swap(unique_any& rhs) noexcept { content.swap(rhs.content); } /// \returns `true` if instance is not empty, otherwise `false`. /// \throws Nothing. - bool has_value() const noexcept + BOOST_ANY_IMPL_CONSTEXPR bool has_value() const noexcept { return !!content; } @@ -210,7 +210,7 @@ class unique_any { /// /// Useful for querying against types known either at compile time or /// only at runtime. - const boost::typeindex::type_info& type() const noexcept + BOOST_ANY_IMPL_CONSTEXPR const boost::typeindex::type_info& type() const noexcept { return content ? content->type() : boost::typeindex::type_id().type_info(); } @@ -222,18 +222,18 @@ class unique_any { { public: template - holder(Args&&... args) + BOOST_ANY_IMPL_CONSTEXPR holder(Args&&... args) : held(std::forward(args)...) { } template - holder(std::initializer_list il, Args&&... args) + BOOST_ANY_IMPL_CONSTEXPR holder(std::initializer_list il, Args&&... args) : held(il, std::forward(args)...) { } - const boost::typeindex::type_info& type() const noexcept override + BOOST_ANY_IMPL_CONSTEXPR const boost::typeindex::type_info& type() const noexcept override { return boost::typeindex::type_id().type_info(); } @@ -244,7 +244,7 @@ class unique_any { private: // representation template - friend T * unsafe_any_cast(unique_any *) noexcept; + friend BOOST_ANY_IMPL_CONSTEXPR T * unsafe_any_cast(unique_any *) noexcept; std::unique_ptr content; /// @endcond @@ -252,7 +252,7 @@ class unique_any { /// Exchange of the contents of `lhs` and `rhs`. /// \throws Nothing. -inline void swap(unique_any & lhs, unique_any & rhs) noexcept +BOOST_ANY_IMPL_CONSTEXPR inline void swap(unique_any & lhs, unique_any & rhs) noexcept { lhs.swap(rhs); } @@ -265,7 +265,7 @@ inline void swap(unique_any & lhs, unique_any & rhs) noexcept // use typeid() comparison, e.g., when our types may travel across // different shared libraries. template -inline T * unsafe_any_cast(unique_any * operand) noexcept +BOOST_ANY_IMPL_CONSTEXPR inline T * unsafe_any_cast(unique_any * operand) noexcept { return std::addressof( static_cast&>(*operand->content).held @@ -273,7 +273,7 @@ inline T * unsafe_any_cast(unique_any * operand) noexcept } template -inline const T * unsafe_any_cast(const unique_any * operand) noexcept +BOOST_ANY_IMPL_CONSTEXPR inline const T * unsafe_any_cast(const unique_any * operand) noexcept { return anys::unsafe_any_cast(const_cast(operand)); } @@ -282,7 +282,7 @@ inline const T * unsafe_any_cast(const unique_any * operand) noexcept /// \returns Pointer to a `T` stored in `operand`, nullptr if /// `operand` does not contain specified `T`. template -T * any_cast(unique_any * operand) noexcept +BOOST_ANY_IMPL_CONSTEXPR T * any_cast(unique_any * operand) noexcept { return operand && operand->type() == boost::typeindex::type_id() ? anys::unsafe_any_cast::type>(operand) @@ -292,7 +292,7 @@ T * any_cast(unique_any * operand) noexcept /// \returns Const pointer to a `T` stored in `operand`, nullptr if /// `operand` does not contain specified `T`. template -inline const T * any_cast(const unique_any * operand) noexcept +BOOST_ANY_IMPL_CONSTEXPR inline const T * any_cast(const unique_any * operand) noexcept { return anys::any_cast(const_cast(operand)); } @@ -300,7 +300,7 @@ inline const T * any_cast(const unique_any * operand) noexcept /// \returns `T` stored in `operand` /// \throws boost::bad_any_cast if `operand` does not contain specified `T`. template -T any_cast(unique_any & operand) +BOOST_ANY_IMPL_CONSTEXPR T any_cast(unique_any & operand) { using nonref = typename std::remove_reference::type; @@ -331,7 +331,7 @@ T any_cast(unique_any & operand) /// \returns `T` stored in `operand` /// \throws boost::bad_any_cast if `operand` does not contain specified `T`. template -inline T any_cast(const unique_any & operand) +BOOST_ANY_IMPL_CONSTEXPR inline T any_cast(const unique_any & operand) { using nonref = typename std::remove_reference::type; return anys::any_cast(const_cast(operand)); @@ -340,7 +340,7 @@ inline T any_cast(const unique_any & operand) /// \returns `T` stored in `operand` /// \throws boost::bad_any_cast if `operand` does not contain specified `T`. template -inline T any_cast(unique_any&& operand) +BOOST_ANY_IMPL_CONSTEXPR inline T any_cast(unique_any&& operand) { static_assert( std::is_rvalue_reference::value /*true if T is rvalue or just a value*/ diff --git a/test/unique_any/base.cpp b/test/unique_any/base.cpp index c615301..e506d43 100644 --- a/test/unique_any/base.cpp +++ b/test/unique_any/base.cpp @@ -125,6 +125,37 @@ void test_swap() { BOOST_TEST_EQ(boost::any_cast&>(a).data(), vec_data); } +#ifdef __cpp_lib_constexpr_new +constexpr int test_constexpr() { + int failures = 0; + boost::anys::unique_any a; + + failures += (!a.has_value() ? 0 : 1); + + auto& i = a.emplace(42); + failures += (i == 42 ? 0 : 1); + failures += (a.has_value() ? 0 : 1); + failures += (boost::any_cast(a) == 42 ? 0 : 1); + failures += (boost::any_cast(a) == 42 ? 0 : 1); + failures += (boost::anys::any_cast(a) == 42 ? 0 : 1); + + boost::anys::unique_any b = std::move(a); + failures += (!a.has_value() ? 0 : 1); + failures += (b.has_value() ? 0 : 1); + failures += (boost::anys::any_cast(b) == 42 ? 0 : 1); + + a = std::move(b); + failures += (a.has_value() ? 0 : 1); + failures += (!b.has_value() ? 0 : 1); + + a.reset(); + failures += (!a.has_value() ? 0 : 1); + failures += (!b.has_value() ? 0 : 1); + + return failures; +} +#endif + int main() { test_basic(); test_const(); @@ -132,6 +163,10 @@ int main() { test_destructor(); test_swap(); +#ifdef __cpp_lib_constexpr_new + static_assert(test_constexpr() == 0); +#endif + return boost::report_errors(); } From bf38e0646b816c8e2339fc56e593c2dcd60ebd5b Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Tue, 13 Oct 2026 20:49:28 +0300 Subject: [PATCH 2/3] More tests and fixes --- include/boost/any.hpp | 4 +- include/boost/any/detail/config.hpp | 2 +- include/boost/any/unique_any.hpp | 2 +- test/any_test.cpp | 65 +++++++++++++++++++++++++++++ test/unique_any/base.cpp | 58 ++++++++++++++++++------- 5 files changed, 112 insertions(+), 19 deletions(-) diff --git a/include/boost/any.hpp b/include/boost/any.hpp index c940449..b09e88d 100644 --- a/include/boost/any.hpp +++ b/include/boost/any.hpp @@ -156,7 +156,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT /// /// \post `rhs->empty()` is true /// \throws Nothing. - any & operator=(any&& rhs) noexcept + BOOST_ANY_IMPL_CONSTEXPR any & operator=(any&& rhs) noexcept { rhs.swap(*this); any().swap(rhs); @@ -255,7 +255,7 @@ BOOST_ANY_BEGIN_MODULE_EXPORT private: // representation template - friend ValueType * unsafe_any_cast(any *) noexcept; + friend BOOST_ANY_IMPL_CONSTEXPR ValueType * unsafe_any_cast(any *) noexcept; friend class boost::anys::unique_any; diff --git a/include/boost/any/detail/config.hpp b/include/boost/any/detail/config.hpp index 25bbb6b..fe07854 100644 --- a/include/boost/any/detail/config.hpp +++ b/include/boost/any/detail/config.hpp @@ -13,7 +13,7 @@ # endif #endif -#ifdef __cpp_lib_constexpr_new +#if defined(__cpp_lib_constexpr_new) || defined(BOOST_ANY_DOXYGEN_INVOKED) #define BOOST_ANY_IMPL_CONSTEXPR constexpr #else #define BOOST_ANY_IMPL_CONSTEXPR diff --git a/include/boost/any/unique_any.hpp b/include/boost/any/unique_any.hpp index 34ba70f..a0921a6 100644 --- a/include/boost/any/unique_any.hpp +++ b/include/boost/any/unique_any.hpp @@ -95,7 +95,7 @@ class unique_any { /// \throws Nothing. /// \post `value.empty()` is true. template - BOOST_ANY_IMPL_CONSTEXPR unique_any(BoostAny&& value, typename std::enable_if::value>::type* = nullptr) noexcept + unique_any(BoostAny&& value, typename std::enable_if::value>::type* = nullptr) noexcept { content.reset(value.content); value.content = nullptr; diff --git a/test/any_test.cpp b/test/any_test.cpp index 2c0b38b..4cf8f3d 100644 --- a/test/any_test.cpp +++ b/test/any_test.cpp @@ -55,9 +55,74 @@ static void test_with_func() s = boost::any_cast(returning_string2()); } + + +#ifdef __cpp_lib_constexpr_new + +#define BOOST_ANY_IMPL_CONSTEXPR_ASSERT(X) \ + if (!(X)) throw std::runtime_error(#X " is false at " + std::to_string(__LINE__)) + +constexpr int test_constexpr() { + boost::any a; + + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(a.empty()); + + a = 42; + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!a.empty()); + + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(a) == 42); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(*boost::unsafe_any_cast(&a) == 42); + + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(&a) == nullptr); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(a) == 42); + + boost::any b = std::move(a); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(a.empty()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!b.empty()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(b) == 42); + + a = std::move(b); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!a.empty()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(b.empty()); + + a.clear(); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(a.empty()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(b.empty()); + + a = 43; + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!a.empty()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(a) == 43); + + a.swap(b); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(a.empty()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!b.empty()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(b) == 43); + + a.swap(b); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!a.empty()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(b.empty()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(a) == 43); + + b = a; + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!a.empty()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!b.empty()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(a) == 43); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(b) == 43); + + return 0; +} + +#undef BOOST_ANY_IMPL_CONSTEXPR_ASSERT + +#endif + int main() { test_with_func(); +#ifdef __cpp_lib_constexpr_new + static_assert(test_constexpr() == 0); +#endif + return any_tests::basic_tests::run_tests(); } diff --git a/test/unique_any/base.cpp b/test/unique_any/base.cpp index e506d43..879305f 100644 --- a/test/unique_any/base.cpp +++ b/test/unique_any/base.cpp @@ -126,34 +126,62 @@ void test_swap() { } #ifdef __cpp_lib_constexpr_new + +#define BOOST_ANY_IMPL_CONSTEXPR_ASSERT(X) \ + if (!(X)) throw std::runtime_error(#X " is false at " + std::to_string(__LINE__)) + constexpr int test_constexpr() { - int failures = 0; boost::anys::unique_any a; - failures += (!a.has_value() ? 0 : 1); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!a.has_value()); auto& i = a.emplace(42); - failures += (i == 42 ? 0 : 1); - failures += (a.has_value() ? 0 : 1); - failures += (boost::any_cast(a) == 42 ? 0 : 1); - failures += (boost::any_cast(a) == 42 ? 0 : 1); - failures += (boost::anys::any_cast(a) == 42 ? 0 : 1); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(i == 42); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(a.has_value()); + + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(a) == 42); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(*boost::unsafe_any_cast(&a) == 42); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::anys::any_cast(a) == 42); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(*boost::anys::unsafe_any_cast(&a) == 42); + + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(&a) == nullptr); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::anys::any_cast(&a) == nullptr); + + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(a) == 42); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::anys::any_cast(a) == 42); boost::anys::unique_any b = std::move(a); - failures += (!a.has_value() ? 0 : 1); - failures += (b.has_value() ? 0 : 1); - failures += (boost::anys::any_cast(b) == 42 ? 0 : 1); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!a.has_value()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(b.has_value()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::anys::any_cast(b) == 42); a = std::move(b); - failures += (a.has_value() ? 0 : 1); - failures += (!b.has_value() ? 0 : 1); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(a.has_value()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!b.has_value()); a.reset(); - failures += (!a.has_value() ? 0 : 1); - failures += (!b.has_value() ? 0 : 1); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!a.has_value()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!b.has_value()); - return failures; + a = 43; + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(a.has_value()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(a) == 43); + + a.swap(b); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!a.has_value()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(b.has_value()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(b) == 43); + + a.swap(b); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(a.has_value()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!b.has_value()); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(a) == 43); + + return 0; } + +#undef BOOST_ANY_IMPL_CONSTEXPR_ASSERT + #endif int main() { From 4879c639811a21f88db89ee0a90e604684b926e6 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Wed, 14 Oct 2026 22:35:09 +0300 Subject: [PATCH 3/3] add tests with const --- test/any_test.cpp | 3 +++ test/unique_any/base.cpp | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/test/any_test.cpp b/test/any_test.cpp index 4cf8f3d..8ea5f2b 100644 --- a/test/any_test.cpp +++ b/test/any_test.cpp @@ -109,6 +109,9 @@ constexpr int test_constexpr() { BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(a) == 43); BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(b) == 43); + const boost::any ca = 44; + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(ca) == 44); + return 0; } diff --git a/test/unique_any/base.cpp b/test/unique_any/base.cpp index 879305f..5bfa261 100644 --- a/test/unique_any/base.cpp +++ b/test/unique_any/base.cpp @@ -177,6 +177,10 @@ constexpr int test_constexpr() { BOOST_ANY_IMPL_CONSTEXPR_ASSERT(!b.has_value()); BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(a) == 43); + const boost::anys::unique_any ca = 44; + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::any_cast(ca) == 44); + BOOST_ANY_IMPL_CONSTEXPR_ASSERT(boost::anys::any_cast(ca) == 44); + return 0; }