diff --git a/include/boost/pfr/detail/fields_count.hpp b/include/boost/pfr/detail/fields_count.hpp index a16b194f..cf201854 100644 --- a/include/boost/pfr/detail/fields_count.hpp +++ b/include/boost/pfr/detail/fields_count.hpp @@ -16,6 +16,7 @@ import std; #else #include // CHAR_BIT +#include // SIZE_MAX #include #include // metaprogramming stuff #endif @@ -30,6 +31,12 @@ import std; namespace boost { namespace pfr { namespace detail { +///////////////////// min without including +template +constexpr const T& (min)(const T& a, const T& b) { + return b < a ? b : a; +} + ///////////////////// Structure that can be converted to reference to anything struct ubiq_lref_constructor { std::size_t ignore; @@ -50,6 +57,14 @@ struct ubiq_rref_constructor { } }; +///////////////////// Hand-made is_complete trait +template +struct is_complete : std::integral_constant +{}; + +template +struct is_complete : std::integral_constant +{}; #ifndef __cpp_lib_is_aggregate ///////////////////// Hand-made is_aggregate_initializable_n trait @@ -78,8 +93,16 @@ template struct is_single_field_and_aggregate_initializable<1, T>: std // Before C++20 aggregates could be constructed from `decltype(ubiq_?ref_constructor{I})...` but type traits report that // there's no constructor from `decltype(ubiq_?ref_constructor{I})...` // Special case for N == 1: `std::is_constructible` returns true if N == 1 and T is copy/move constructible. -template +template struct is_aggregate_initializable_n { + static constexpr bool value = + std::is_empty::value + || std::is_array::value + ; +}; + +template +struct is_aggregate_initializable_n::value && !std::is_empty::value>::type> { template static constexpr bool is_not_constructible_n(std::index_sequence) noexcept { return (!std::is_constructible::value && !std::is_constructible::value) @@ -87,12 +110,7 @@ struct is_aggregate_initializable_n { ; } - static constexpr bool value = - std::is_empty::value - || std::is_array::value - || std::is_fundamental::value - || is_not_constructible_n(detail::make_index_sequence{}) - ; + static constexpr bool value = is_not_constructible_n(detail::make_index_sequence{}); }; #endif // #ifndef __cpp_lib_is_aggregate @@ -151,17 +169,40 @@ constexpr void* assert_first_not_base(std::index_sequence<>) noexcept return nullptr; } -///////////////////// Helper for SFINAE on fields count +template +constexpr void assert_first_not_base(int) noexcept {} + +template +constexpr auto assert_first_not_base(long) noexcept + -> typename std::enable_if::value>::type +{ + detail::assert_first_not_base(detail::make_index_sequence{}); +} + +///////////////////// Helpers for initializable detection +// Note that these take O(N) compile time and memory! template ::value>::type> -constexpr auto enable_if_constructible_helper(std::index_sequence) noexcept - -> typename std::add_pointer::type; +constexpr auto enable_if_initializable_helper(std::index_sequence) noexcept + -> typename std::add_pointer::type; template ::value>::type> -constexpr auto enable_if_constructible_helper(std::index_sequence) noexcept - -> typename std::add_pointer::type; +constexpr auto enable_if_initializable_helper(std::index_sequence) noexcept + -> typename std::add_pointer::type; + +template (detail::make_index_sequence()))> +using enable_if_initializable_helper_t = U; -template (detail::make_index_sequence()) ) > -using enable_if_constructible_helper_t = std::size_t; +template +constexpr auto is_initializable(long) noexcept + -> detail::enable_if_initializable_helper_t +{ + return true; +} + +template +constexpr bool is_initializable(int) noexcept { + return false; +} ///////////////////// Helpers for range size detection template @@ -170,9 +211,26 @@ using is_one_element_range = std::integral_constant; using multi_element_range = std::false_type; using one_element_range = std::true_type; -///////////////////// Non greedy fields count search. Templates instantiation depth is log(sizeof(T)), templates instantiation count is log(sizeof(T)). + +///////////////////// Fields count next expected compiler limitation +constexpr std::size_t fields_count_compiler_limitation_next(std::size_t n) noexcept { +#if defined(_MSC_VER) && (_MSC_VER <= 1920) + if (n < 1024) + return 1024; +#endif + return SIZE_MAX; +} + +///////////////////// Fields count upper bound based on sizeof(T) +template +constexpr std::size_t fields_count_upper_bound_loose() noexcept { + return sizeof(T) * CHAR_BIT; +} + +///////////////////// Fields count binary search. +// Template instantiation: depth is O(log(result)), count is O(log(result)), cost is O(result * log(result)). template -constexpr std::size_t detect_fields_count(detail::one_element_range, long) noexcept { +constexpr std::size_t fields_count_binary_search(detail::one_element_range, long) noexcept { static_assert( Begin == Middle, "====================> Boost.PFR: Internal logic error." @@ -181,81 +239,127 @@ constexpr std::size_t detect_fields_count(detail::one_element_range, long) noexc } template -constexpr std::size_t detect_fields_count(detail::multi_element_range, int) noexcept; +constexpr std::size_t fields_count_binary_search(detail::multi_element_range, int) noexcept; template -constexpr auto detect_fields_count(detail::multi_element_range, long) noexcept - -> detail::enable_if_constructible_helper_t +constexpr auto fields_count_binary_search(detail::multi_element_range, long) noexcept + -> detail::enable_if_initializable_helper_t { constexpr std::size_t next_v = Middle + (Middle - Begin + 1) / 2; - return detail::detect_fields_count(detail::is_one_element_range{}, 1L); + return detail::fields_count_binary_search(detail::is_one_element_range{}, 1L); } template -constexpr std::size_t detect_fields_count(detail::multi_element_range, int) noexcept { +constexpr std::size_t fields_count_binary_search(detail::multi_element_range, int) noexcept { constexpr std::size_t next_v = Begin + (Middle - Begin) / 2; - return detail::detect_fields_count(detail::is_one_element_range{}, 1L); + return detail::fields_count_binary_search(detail::is_one_element_range{}, 1L); } -///////////////////// Greedy search. Templates instantiation depth is log(sizeof(T)), templates instantiation count is log(sizeof(T))*T in worst case. -template -constexpr auto detect_fields_count_greedy_remember(long) noexcept - -> detail::enable_if_constructible_helper_t +template +constexpr std::size_t fields_count_upper_bound(int, int) noexcept { + return N - 1; +} + +template +constexpr auto fields_count_upper_bound(long, long) noexcept + -> std::enable_if_t<(N > detail::fields_count_upper_bound_loose()), std::size_t> { - return N; + static_assert( + !detail::is_initializable() + 1>(1L), + "====================> Boost.PFR: Types with user specified constructors (non-aggregate initializable types) are not supported."); + return detail::fields_count_upper_bound_loose(); } -template -constexpr std::size_t detect_fields_count_greedy_remember(int) noexcept { - return 0; +template +constexpr auto fields_count_upper_bound(long, int) noexcept + -> detail::enable_if_initializable_helper_t +{ + constexpr std::size_t next_optimal = Begin + (N - Begin) * 2; + constexpr std::size_t next = (detail::min)(next_optimal, detail::fields_count_compiler_limitation_next(N)); + return detail::fields_count_upper_bound(1L, 1L); +} + +template +constexpr std::size_t fields_count_binary_search_unbounded() noexcept { + constexpr std::size_t last = detail::fields_count_upper_bound(1L, 1L); + constexpr std::size_t middle = (Begin + last + 1) / 2; + return detail::fields_count_binary_search(detail::is_one_element_range{}, 1L); +} + +///////////////////// Fields count lower bound linear search. +// Template instantiation: depth is O(log(result)), count is O(result), cost is O(result^2). +template +constexpr std::size_t fields_count_lower_bound(RangeSize, size_t_) noexcept { + return Result; } template -constexpr std::size_t detect_fields_count_greedy(detail::one_element_range) noexcept { +constexpr std::size_t fields_count_lower_bound(detail::one_element_range, size_t_<0> = {}) noexcept { static_assert( Begin == Last, "====================> Boost.PFR: Internal logic error." ); - return detail::detect_fields_count_greedy_remember(1L); + return detail::is_initializable(1L) ? Begin : 0; } template -constexpr std::size_t detect_fields_count_greedy(detail::multi_element_range) noexcept { +constexpr std::size_t fields_count_lower_bound(detail::multi_element_range, size_t_<0> = {}) noexcept { + // Binary partition to limit template depth. constexpr std::size_t middle = Begin + (Last - Begin) / 2; - constexpr std::size_t fields_count_big_range = detail::detect_fields_count_greedy( - detail::is_one_element_range{} + constexpr std::size_t result_maybe = detail::fields_count_lower_bound( + detail::is_one_element_range{} + ); + return detail::fields_count_lower_bound( + detail::is_one_element_range{}, + size_t_{} ); +} + +template +constexpr std::size_t fields_count_lower_bound_unbounded(int, size_t_) noexcept { + return Result; +} - constexpr std::size_t small_range_begin = (fields_count_big_range ? 0 : Begin); - constexpr std::size_t small_range_last = (fields_count_big_range ? 0 : middle); - constexpr std::size_t fields_count_small_range = detail::detect_fields_count_greedy( - detail::is_one_element_range{} +template +constexpr auto fields_count_lower_bound_unbounded(long, size_t_<0> = {}) noexcept + -> std::enable_if_t<(Begin >= detail::fields_count_upper_bound_loose()), std::size_t> +{ + static_assert( + detail::is_initializable()>(1L), + "====================> Boost.PFR: Type must be aggregate initializable."); + return detail::fields_count_upper_bound_loose(); +} + +template +constexpr std::size_t fields_count_lower_bound_unbounded(int, size_t_<0> = {}) noexcept { + constexpr std::size_t last = (detail::min)(Begin * 2, detail::fields_count_upper_bound_loose()) - 1; + constexpr std::size_t result_maybe = detail::fields_count_lower_bound( + detail::is_one_element_range{} ); - return fields_count_big_range ? fields_count_big_range : fields_count_small_range; + return detail::fields_count_lower_bound_unbounded(1L, size_t_{}); } -///////////////////// Choosing between array size, greedy and non greedy search. -template -constexpr auto detect_fields_count_dispatch(size_t_, long, long) noexcept +///////////////////// Choosing between array size, unbounded binary search, and linear search followed by unbounded binary search. +template +constexpr auto fields_count_dispatch(long, long) noexcept -> typename std::enable_if::value, std::size_t>::type { return sizeof(T) / sizeof(typename std::remove_all_extents::type); } -template -constexpr auto detect_fields_count_dispatch(size_t_, long, int) noexcept +template +constexpr auto fields_count_dispatch(long, int) noexcept -> decltype(sizeof(T{})) { - constexpr std::size_t middle = N / 2 + 1; - return detail::detect_fields_count(detail::multi_element_range{}, 1L); + return detail::fields_count_binary_search_unbounded(); } -template -constexpr std::size_t detect_fields_count_dispatch(size_t_, int, int) noexcept { - // T is not default aggregate initialzable. It means that at least one of the members is not default constructible, - // so we have to check all the aggregate initializations for T up to N parameters and return the bigest succeeded - // (we can not use binary search for detecting fields count). - return detail::detect_fields_count_greedy(detail::multi_element_range{}); +template +constexpr std::size_t fields_count_dispatch(int, int) noexcept { + // T is not default aggregate initializable. This means that at least one of the members is not default-constructible. + // Use linear search to find the smallest valid initializer, after which we unbounded binary search for the largest. + constexpr std::size_t begin = detail::fields_count_lower_bound_unbounded(1L); + return detail::fields_count_binary_search_unbounded(); } ///////////////////// Returns fields count @@ -263,6 +367,11 @@ template constexpr std::size_t fields_count() noexcept { using type = std::remove_cv_t; + static_assert( + detail::is_complete::value, + "====================> Boost.PFR: Type must be complete." + ); + static_assert( !std::is_reference::value, "====================> Boost.PFR: Attempt to get fields count on a reference. This is not allowed because that could hide an issue and different library users expect different behavior in that case." @@ -299,20 +408,14 @@ constexpr std::size_t fields_count() noexcept { // ); //#endif -#if defined(_MSC_VER) && (_MSC_VER <= 1920) - // Workaround for msvc compilers. Versions <= 1920 have a limit of max 1024 elements in template parameter pack - constexpr std::size_t max_fields_count = (sizeof(type) * CHAR_BIT >= 1024 ? 1024 : sizeof(type) * CHAR_BIT); -#else - constexpr std::size_t max_fields_count = (sizeof(type) * CHAR_BIT); // We multiply by CHAR_BIT because the type may have bitfields in T -#endif - - constexpr std::size_t result = detail::detect_fields_count_dispatch(size_t_{}, 1L, 1L); + constexpr std::size_t result = detail::fields_count_dispatch(1L, 1L); - detail::assert_first_not_base(detail::make_index_sequence{}); + detail::assert_first_not_base(1L); #ifndef __cpp_lib_is_aggregate static_assert( - is_aggregate_initializable_n::value, + detail::is_aggregate_initializable_n::value // Does not return `true` for built-in types. + || std::is_scalar::value, "====================> Boost.PFR: Types with user specified constructors (non-aggregate initializable types) are not supported." ); #endif diff --git a/test/core/Jamfile.v2 b/test/core/Jamfile.v2 index a4a04ee5..50c17bd4 100644 --- a/test/core/Jamfile.v2 +++ b/test/core/Jamfile.v2 @@ -70,6 +70,10 @@ test-suite pfr_tests [ run ../../example/sample_printing.cpp : : : : auto_engine_sample_printing ] [ run ../../example/get.cpp : : : : auto_engine_get ] [ run ../../example/quick_examples.cpp : : : : auto_engine_quick ] + + [ compile-fail fields_count_on_incomplete_type.cpp : BOOST_PFR_RUN_TEST_ON=void : fields_count_on_incomplete_type_void ] + [ compile-fail fields_count_on_incomplete_type.cpp : BOOST_PFR_RUN_TEST_ON="void()" : fields_count_on_incomplete_type_function ] + [ compile-fail fields_count_on_incomplete_type.cpp : BOOST_PFR_RUN_TEST_ON="struct Foo" : fields_count_on_incomplete_type_struct ] ; local BLACKLIST_TESTS_FOR_LOOPHOLE = diff --git a/test/core/compile-fail/constructible_0_or_more_args.cpp b/test/core/compile-fail/constructible_0_or_more_args.cpp new file mode 100644 index 00000000..715ac7ab --- /dev/null +++ b/test/core/compile-fail/constructible_0_or_more_args.cpp @@ -0,0 +1,15 @@ +// Copyright (c) 2023-2024 Antony Polukhin +// +// 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) + +#include + +struct A { + template + explicit A(Args&&...) {} +}; + +int main() { + (void)boost::pfr::tuple_size::value; // Must be a compile time error +} diff --git a/test/core/compile-fail/constructible_1_or_more_args.cpp b/test/core/compile-fail/constructible_1_or_more_args.cpp new file mode 100644 index 00000000..177043b5 --- /dev/null +++ b/test/core/compile-fail/constructible_1_or_more_args.cpp @@ -0,0 +1,15 @@ +// Copyright (c) 2023-2024 Antony Polukhin +// +// 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) + +#include + +struct A { + template + explicit A(Arg0&&, Args&&...) {} +}; + +int main() { + (void)boost::pfr::tuple_size::value; // Must be a compile time error +} diff --git a/test/core/fields_count_on_incomplete_type.cpp b/test/core/fields_count_on_incomplete_type.cpp new file mode 100644 index 00000000..52f88d97 --- /dev/null +++ b/test/core/fields_count_on_incomplete_type.cpp @@ -0,0 +1,10 @@ +// Copyright (c) 2023-2024 Antony Polukhin +// +// 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) + +#include + +int main() { + return static_cast(boost::pfr::detail::fields_count()); +} diff --git a/test/core/run/bitfields_count.cpp b/test/core/run/bitfields_count.cpp index ff62e5ec..12863e25 100644 --- a/test/core/run/bitfields_count.cpp +++ b/test/core/run/bitfields_count.cpp @@ -5,17 +5,82 @@ #include -struct bf { - unsigned int i1: 1; - unsigned int i2: 1; - unsigned int i3: 1; - unsigned int i4: 1; - unsigned int i5: 1; - unsigned int i6: 1; +#include + +struct bf7 { + uint8_t b0 : 1; + uint8_t b1 : 1; + uint8_t b2 : 1; + uint8_t b3 : 1; + uint8_t b4 : 1; + uint8_t b5 : 1; + uint8_t b6 : 1; }; +static_assert(sizeof(bf7) == 1, ""); -int main() { - static_assert(boost::pfr::tuple_size::value == 6, ""); -} +struct bf8 { + uint8_t b0 : 1; + uint8_t b1 : 1; + uint8_t b2 : 1; + uint8_t b3 : 1; + uint8_t b4 : 1; + uint8_t b5 : 1; + uint8_t b6 : 1; + uint8_t b7 : 1; +}; +static_assert(sizeof(bf8) == 1, ""); +struct bf16 { + uint8_t b0 : 1; + uint8_t b1 : 1; + uint8_t b2 : 1; + uint8_t b3 : 1; + uint8_t b4 : 1; + uint8_t b5 : 1; + uint8_t b6 : 1; + uint8_t b7 : 1; + uint8_t b8 : 1; + uint8_t b9 : 1; + uint8_t b10 : 1; + uint8_t b11 : 1; + uint8_t b12 : 1; + uint8_t b13 : 1; + uint8_t b14 : 1; + uint8_t b15 : 1; +}; +static_assert(sizeof(bf16) == 2, ""); +struct bf24 { + uint8_t b0 : 1; + uint8_t b1 : 1; + uint8_t b2 : 1; + uint8_t b3 : 1; + uint8_t b4 : 1; + uint8_t b5 : 1; + uint8_t b6 : 1; + uint8_t b7 : 1; + uint8_t b8 : 1; + uint8_t b9 : 1; + uint8_t b10 : 1; + uint8_t b11 : 1; + uint8_t b12 : 1; + uint8_t b13 : 1; + uint8_t b14 : 1; + uint8_t b15 : 1; + uint8_t b16 : 1; + uint8_t b17 : 1; + uint8_t b18 : 1; + uint8_t b19 : 1; + uint8_t b20 : 1; + uint8_t b21 : 1; + uint8_t b22 : 1; + uint8_t b23 : 1; +}; +static_assert(sizeof(bf24) == 3, ""); + +int main() { + static_assert(boost::pfr::tuple_size_v == 7, ""); + static_assert(boost::pfr::tuple_size_v == 8, ""); + static_assert(boost::pfr::tuple_size_v == 16, ""); + static_assert(boost::pfr::tuple_size_v == 24, ""); +} diff --git a/test/core/run/huge_count.cpp b/test/core/run/huge_count.cpp new file mode 100644 index 00000000..ef039133 --- /dev/null +++ b/test/core/run/huge_count.cpp @@ -0,0 +1,63 @@ +// Copyright (c) 2024 Antony Polukhin +// +// 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) + +#include + +#include +#include + +#if defined(__clang__) +# if SIZE_MAX > (1ULL << 32) - 1 +# define ARRAY_MAX (SIZE_MAX >> 3) +# else +# define ARRAY_MAX SIZE_MAX +# endif +# define OBJECT_MAX SIZE_MAX +#elif defined(__GNUC__) +# define ARRAY_MAX INT_MAX +# define OBJECT_MAX (SIZE_MAX >> 1) +#elif defined(_MSC_VER) +# define ARRAY_MAX INT_MAX +# define OBJECT_MAX UINT_MAX +#else // Let's play it safe +# define ARRAY_MAX INT_MAX +# define OBJECT_MAX INT_MAX +#endif + +#pragma pack(1) +struct A { + char x[ARRAY_MAX <= (OBJECT_MAX >> 3) ? ARRAY_MAX : OBJECT_MAX >> 3]; +}; + +struct B { + A a; + A b; + A c; + A d; + A e; + A f; + A g; + A h; +}; + +struct C { + A& a; + A b; + A c; + A d; + A e; + A f; + A g; + A h; +}; +#pragma pack() + +int main() { +#ifndef _MSC_VER + static_assert(boost::pfr::tuple_size_v == ARRAY_MAX, ""); +#endif + static_assert(boost::pfr::tuple_size_v == 8, ""); + static_assert(boost::pfr::tuple_size_v == 8, ""); +} diff --git a/test/core/run/many_fields_count.cpp b/test/core/run/many_fields_count.cpp new file mode 100644 index 00000000..725bf72e --- /dev/null +++ b/test/core/run/many_fields_count.cpp @@ -0,0 +1,1019 @@ +// Copyright (c) 2024 Antony Polukhin +// +// 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) + +#include + +#include + +#pragma pack(1) +struct struct_1k_fields +{ + int a0; + int a1; + int a2; + int a3; + int a4; + int a5; + int a6; + int a7; + int a8; + int a9; + int a10; + int a11; + int a12; + int a13; + int a14; + int a15; + int a16; + int a17; + int a18; + int a19; + int a20; + int a21; + int a22; + int a23; + int a24; + int a25; + int a26; + int a27; + int a28; + int a29; + int a30; + int a31; + int a32; + int a33; + int a34; + int a35; + int a36; + int a37; + int a38; + int a39; + int a40; + int a41; + int a42; + int a43; + int a44; + int a45; + int a46; + int a47; + int a48; + int a49; + int a50; + int a51; + int a52; + int a53; + int a54; + int a55; + int a56; + int a57; + int a58; + int a59; + int a60; + int a61; + int a62; + int a63; + int a64; + int a65; + int a66; + int a67; + int a68; + int a69; + int a70; + int a71; + int a72; + int a73; + int a74; + int a75; + int a76; + int a77; + int a78; + int a79; + int a80; + int a81; + int a82; + int a83; + int a84; + int a85; + int a86; + int a87; + int a88; + int a89; + int a90; + int a91; + int a92; + int a93; + int a94; + int a95; + int a96; + int a97; + int a98; + int a99; + int a100; + int a101; + int a102; + int a103; + int a104; + int a105; + int a106; + int a107; + int a108; + int a109; + int a110; + int a111; + int a112; + int a113; + int a114; + int a115; + int a116; + int a117; + int a118; + int a119; + int a120; + int a121; + int a122; + int a123; + int a124; + int a125; + int a126; + int a127; + int a128; + int a129; + int a130; + int a131; + int a132; + int a133; + int a134; + int a135; + int a136; + int a137; + int a138; + int a139; + int a140; + int a141; + int a142; + int a143; + int a144; + int a145; + int a146; + int a147; + int a148; + int a149; + int a150; + int a151; + int a152; + int a153; + int a154; + int a155; + int a156; + int a157; + int a158; + int a159; + int a160; + int a161; + int a162; + int a163; + int a164; + int a165; + int a166; + int a167; + int a168; + int a169; + int a170; + int a171; + int a172; + int a173; + int a174; + int a175; + int a176; + int a177; + int a178; + int a179; + int a180; + int a181; + int a182; + int a183; + int a184; + int a185; + int a186; + int a187; + int a188; + int a189; + int a190; + int a191; + int a192; + int a193; + int a194; + int a195; + int a196; + int a197; + int a198; + int a199; + int a200; + int a201; + int a202; + int a203; + int a204; + int a205; + int a206; + int a207; + int a208; + int a209; + int a210; + int a211; + int a212; + int a213; + int a214; + int a215; + int a216; + int a217; + int a218; + int a219; + int a220; + int a221; + int a222; + int a223; + int a224; + int a225; + int a226; + int a227; + int a228; + int a229; + int a230; + int a231; + int a232; + int a233; + int a234; + int a235; + int a236; + int a237; + int a238; + int a239; + int a240; + int a241; + int a242; + int a243; + int a244; + int a245; + int a246; + int a247; + int a248; + int a249; + int a250; + int a251; + int a252; + int a253; + int a254; + int a255; + int a256; + int a257; + int a258; + int a259; + int a260; + int a261; + int a262; + int a263; + int a264; + int a265; + int a266; + int a267; + int a268; + int a269; + int a270; + int a271; + int a272; + int a273; + int a274; + int a275; + int a276; + int a277; + int a278; + int a279; + int a280; + int a281; + int a282; + int a283; + int a284; + int a285; + int a286; + int a287; + int a288; + int a289; + int a290; + int a291; + int a292; + int a293; + int a294; + int a295; + int a296; + int a297; + int a298; + int a299; + int a300; + int a301; + int a302; + int a303; + int a304; + int a305; + int a306; + int a307; + int a308; + int a309; + int a310; + int a311; + int a312; + int a313; + int a314; + int a315; + int a316; + int a317; + int a318; + int a319; + int a320; + int a321; + int a322; + int a323; + int a324; + int a325; + int a326; + int a327; + int a328; + int a329; + int a330; + int a331; + int a332; + int a333; + int a334; + int a335; + int a336; + int a337; + int a338; + int a339; + int a340; + int a341; + int a342; + int a343; + int a344; + int a345; + int a346; + int a347; + int a348; + int a349; + int a350; + int a351; + int a352; + int a353; + int a354; + int a355; + int a356; + int a357; + int a358; + int a359; + int a360; + int a361; + int a362; + int a363; + int a364; + int a365; + int a366; + int a367; + int a368; + int a369; + int a370; + int a371; + int a372; + int a373; + int a374; + int a375; + int a376; + int a377; + int a378; + int a379; + int a380; + int a381; + int a382; + int a383; + int a384; + int a385; + int a386; + int a387; + int a388; + int a389; + int a390; + int a391; + int a392; + int a393; + int a394; + int a395; + int a396; + int a397; + int a398; + int a399; + int a400; + int a401; + int a402; + int a403; + int a404; + int a405; + int a406; + int a407; + int a408; + int a409; + int a410; + int a411; + int a412; + int a413; + int a414; + int a415; + int a416; + int a417; + int a418; + int a419; + int a420; + int a421; + int a422; + int a423; + int a424; + int a425; + int a426; + int a427; + int a428; + int a429; + int a430; + int a431; + int a432; + int a433; + int a434; + int a435; + int a436; + int a437; + int a438; + int a439; + int a440; + int a441; + int a442; + int a443; + int a444; + int a445; + int a446; + int a447; + int a448; + int a449; + int a450; + int a451; + int a452; + int a453; + int a454; + int a455; + int a456; + int a457; + int a458; + int a459; + int a460; + int a461; + int a462; + int a463; + int a464; + int a465; + int a466; + int a467; + int a468; + int a469; + int a470; + int a471; + int a472; + int a473; + int a474; + int a475; + int a476; + int a477; + int a478; + int a479; + int a480; + int a481; + int a482; + int a483; + int a484; + int a485; + int a486; + int a487; + int a488; + int a489; + int a490; + int a491; + int a492; + int a493; + int a494; + int a495; + int a496; + int a497; + int a498; + int a499; + int a500; + int a501; + int a502; + int a503; + int a504; + int a505; + int a506; + int a507; + int a508; + int a509; + int a510; + int a511; + int a512; + int a513; + int a514; + int a515; + int a516; + int a517; + int a518; + int a519; + int a520; + int a521; + int a522; + int a523; + int a524; + int a525; + int a526; + int a527; + int a528; + int a529; + int a530; + int a531; + int a532; + int a533; + int a534; + int a535; + int a536; + int a537; + int a538; + int a539; + int a540; + int a541; + int a542; + int a543; + int a544; + int a545; + int a546; + int a547; + int a548; + int a549; + int a550; + int a551; + int a552; + int a553; + int a554; + int a555; + int a556; + int a557; + int a558; + int a559; + int a560; + int a561; + int a562; + int a563; + int a564; + int a565; + int a566; + int a567; + int a568; + int a569; + int a570; + int a571; + int a572; + int a573; + int a574; + int a575; + int a576; + int a577; + int a578; + int a579; + int a580; + int a581; + int a582; + int a583; + int a584; + int a585; + int a586; + int a587; + int a588; + int a589; + int a590; + int a591; + int a592; + int a593; + int a594; + int a595; + int a596; + int a597; + int a598; + int a599; + int a600; + int a601; + int a602; + int a603; + int a604; + int a605; + int a606; + int a607; + int a608; + int a609; + int a610; + int a611; + int a612; + int a613; + int a614; + int a615; + int a616; + int a617; + int a618; + int a619; + int a620; + int a621; + int a622; + int a623; + int a624; + int a625; + int a626; + int a627; + int a628; + int a629; + int a630; + int a631; + int a632; + int a633; + int a634; + int a635; + int a636; + int a637; + int a638; + int a639; + int a640; + int a641; + int a642; + int a643; + int a644; + int a645; + int a646; + int a647; + int a648; + int a649; + int a650; + int a651; + int a652; + int a653; + int a654; + int a655; + int a656; + int a657; + int a658; + int a659; + int a660; + int a661; + int a662; + int a663; + int a664; + int a665; + int a666; + int a667; + int a668; + int a669; + int a670; + int a671; + int a672; + int a673; + int a674; + int a675; + int a676; + int a677; + int a678; + int a679; + int a680; + int a681; + int a682; + int a683; + int a684; + int a685; + int a686; + int a687; + int a688; + int a689; + int a690; + int a691; + int a692; + int a693; + int a694; + int a695; + int a696; + int a697; + int a698; + int a699; + int a700; + int a701; + int a702; + int a703; + int a704; + int a705; + int a706; + int a707; + int a708; + int a709; + int a710; + int a711; + int a712; + int a713; + int a714; + int a715; + int a716; + int a717; + int a718; + int a719; + int a720; + int a721; + int a722; + int a723; + int a724; + int a725; + int a726; + int a727; + int a728; + int a729; + int a730; + int a731; + int a732; + int a733; + int a734; + int a735; + int a736; + int a737; + int a738; + int a739; + int a740; + int a741; + int a742; + int a743; + int a744; + int a745; + int a746; + int a747; + int a748; + int a749; + int a750; + int a751; + int a752; + int a753; + int a754; + int a755; + int a756; + int a757; + int a758; + int a759; + int a760; + int a761; + int a762; + int a763; + int a764; + int a765; + int a766; + int a767; + int a768; + int a769; + int a770; + int a771; + int a772; + int a773; + int a774; + int a775; + int a776; + int a777; + int a778; + int a779; + int a780; + int a781; + int a782; + int a783; + int a784; + int a785; + int a786; + int a787; + int a788; + int a789; + int a790; + int a791; + int a792; + int a793; + int a794; + int a795; + int a796; + int a797; + int a798; + int a799; + int a800; + int a801; + int a802; + int a803; + int a804; + int a805; + int a806; + int a807; + int a808; + int a809; + int a810; + int a811; + int a812; + int a813; + int a814; + int a815; + int a816; + int a817; + int a818; + int a819; + int a820; + int a821; + int a822; + int a823; + int a824; + int a825; + int a826; + int a827; + int a828; + int a829; + int a830; + int a831; + int a832; + int a833; + int a834; + int a835; + int a836; + int a837; + int a838; + int a839; + int a840; + int a841; + int a842; + int a843; + int a844; + int a845; + int a846; + int a847; + int a848; + int a849; + int a850; + int a851; + int a852; + int a853; + int a854; + int a855; + int a856; + int a857; + int a858; + int a859; + int a860; + int a861; + int a862; + int a863; + int a864; + int a865; + int a866; + int a867; + int a868; + int a869; + int a870; + int a871; + int a872; + int a873; + int a874; + int a875; + int a876; + int a877; + int a878; + int a879; + int a880; + int a881; + int a882; + int a883; + int a884; + int a885; + int a886; + int a887; + int a888; + int a889; + int a890; + int a891; + int a892; + int a893; + int a894; + int a895; + int a896; + int a897; + int a898; + int a899; + int a900; + int a901; + int a902; + int a903; + int a904; + int a905; + int a906; + int a907; + int a908; + int a909; + int a910; + int a911; + int a912; + int a913; + int a914; + int a915; + int a916; + int a917; + int a918; + int a919; + int a920; + int a921; + int a922; + int a923; + int a924; + int a925; + int a926; + int a927; + int a928; + int a929; + int a930; + int a931; + int a932; + int a933; + int a934; + int a935; + int a936; + int a937; + int a938; + int a939; + int a940; + int a941; + int a942; + int a943; + int a944; + int a945; + int a946; + int a947; + int a948; + int a949; + int a950; + int a951; + int a952; + int a953; + int a954; + int a955; + int a956; + int a957; + int a958; + int a959; + int a960; + int a961; + int a962; + int a963; + int a964; + int a965; + int a966; + int a967; + int a968; + int a969; + int a970; + int a971; + int a972; + int a973; + int a974; + int a975; + int a976; + int a977; + int a978; + int a979; + int a980; + int a981; + int a982; + int a983; + int a984; + int a985; + int a986; + int a987; + int a988; + int a989; + int a990; + int a991; + int a992; + int a993; + int a994; + int a995; + int a996; + int a997; + int a998; + int a999; +}; +#pragma pack() + +int main() +{ + static_assert(boost::pfr::tuple_size_v == 1000, ""); +} diff --git a/test/core/run/template_forwarding_ref.cpp b/test/core/run/template_forwarding_ref.cpp index dfc123bc..8fc06e48 100644 --- a/test/core/run/template_forwarding_ref.cpp +++ b/test/core/run/template_forwarding_ref.cpp @@ -45,7 +45,7 @@ int main() { "Precise reflection with template constructors sanity check fails" ); - boost::pfr::detail::enable_if_constructible_helper_t foo; + boost::pfr::detail::enable_if_initializable_helper_t foo; (void)foo; static_assert( diff --git a/test/core/run/template_unconstrained.cpp b/test/core/run/template_unconstrained.cpp index 161fd627..36099e2a 100644 --- a/test/core/run/template_unconstrained.cpp +++ b/test/core/run/template_unconstrained.cpp @@ -45,7 +45,7 @@ int main() { "Precise reflection with template constructors sanity check fails" ); - boost::pfr::detail::enable_if_constructible_helper_t foo; + boost::pfr::detail::enable_if_initializable_helper_t foo; (void)foo; static_assert(