From 32185b0b7dc23c9252d99b64c1bb0a4bc447f71f Mon Sep 17 00:00:00 2001 From: Arthur O'Dwyer Date: Mon, 29 Jan 2018 15:52:40 -0800 Subject: [PATCH] Add "structured_binding_traits.h" based on ideas from Michael Park. Michael says that something like this code is being used in https://github.com/mpark/patterns I took his code ( https://wandbox.org/permlink/tgjQkyHqzV9p2v3D ), simplified it and lowered it to the C++14 subset accepted by Xcode. --- SG14/structured_binding_traits.h | 71 +++++++++++ SG14_test/SG14_test.h | 1 + SG14_test/main.cpp | 1 + SG14_test/structured_binding_traits_test.cpp | 118 +++++++++++++++++++ cmake/CMakeLists.txt | 1 + 5 files changed, 192 insertions(+) create mode 100644 SG14/structured_binding_traits.h create mode 100644 SG14_test/structured_binding_traits_test.cpp diff --git a/SG14/structured_binding_traits.h b/SG14/structured_binding_traits.h new file mode 100644 index 00000000..4d2a9c72 --- /dev/null +++ b/SG14/structured_binding_traits.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include +#include + +#ifndef AGGREGATE_SIZE_FUDGE + #define AGGREGATE_SIZE_FUDGE 2 +#endif + +#if __cplusplus >= 201703L + #define INLINE_IN_CXX17 inline +#else + #define INLINE_IN_CXX17 +#endif + +namespace stdext { + +#if __cplusplus >= 201703L +using std::is_aggregate; +using std::is_aggregate_v; +#elif __has_extension(is_aggregate) +template struct is_aggregate : std::integral_constant {}; +template INLINE_IN_CXX17 constexpr bool is_aggregate_v = is_aggregate::value; +#else +template struct is_aggregate : std::integral_constant::value || std::is_array::value> {}; +template INLINE_IN_CXX17 constexpr bool is_aggregate_v = is_aggregate::value; +#endif + +namespace detail { + template struct is_tuple_like_impl : std::false_type {}; + template struct is_tuple_like_impl::value))> : std::true_type {}; +} // namespace detail + +template struct is_tuple_like : detail::is_tuple_like_impl {}; +template INLINE_IN_CXX17 constexpr bool is_tuple_like_v = is_tuple_like::value; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +namespace detail { + struct convertible_to_anything { template operator T() const noexcept; }; + template struct is_n_constructible_impl : std::false_type {}; + template struct is_n_constructible_impl, decltype(void(T{(void(Is), convertible_to_anything{})...}))> : std::true_type {}; +} // namespace detail +#pragma GCC diagnostic pop + +template struct is_n_constructible : detail::is_n_constructible_impl, void> {}; +template INLINE_IN_CXX17 constexpr bool is_n_constructible_v = is_n_constructible::value; + +namespace detail { + template struct aggregate_size_impl2 : aggregate_size_impl2> {}; + template struct aggregate_size_impl2 : std::integral_constant {}; + template struct aggregate_size_impl2 {}; + + template struct aggregate_size_impl : aggregate_size_impl2> {}; + template struct aggregate_size_impl {}; +} // namespace detail + +template struct aggregate_size : detail::aggregate_size_impl::value> {}; +template INLINE_IN_CXX17 constexpr auto aggregate_size_v = aggregate_size::value; + +namespace detail { + template struct is_structured_bindable_impl : std::false_type {}; + template struct is_structured_bindable_impl::value && std::tuple_size::value == M>> : std::true_type {}; + template struct is_structured_bindable_impl::value && is_aggregate::value && aggregate_size::value == M>> : std::true_type {}; +} // namespace detail + +template struct is_structured_bindable : detail::is_structured_bindable_impl {}; +template INLINE_IN_CXX17 constexpr bool is_structured_bindable_v = is_structured_bindable::value; + +} // namespace stdext diff --git a/SG14_test/SG14_test.h b/SG14_test/SG14_test.h index d3efd716..bbadd755 100644 --- a/SG14_test/SG14_test.h +++ b/SG14_test/SG14_test.h @@ -7,6 +7,7 @@ namespace sg14_test void plf_colony_test(); void ring_test(); void slot_map_test(); + void structured_binding_traits_test(); void transcode_test(); void uninitialized_test(); void unstable_remove_test(); diff --git a/SG14_test/main.cpp b/SG14_test/main.cpp index f37fa35c..1ad8381a 100644 --- a/SG14_test/main.cpp +++ b/SG14_test/main.cpp @@ -12,6 +12,7 @@ int main(int, char *[]) sg14_test::plf_colony_test(); sg14_test::ring_test(); sg14_test::slot_map_test(); + sg14_test::structured_binding_traits_test(); sg14_test::transcode_test(); sg14_test::uninitialized_test(); sg14_test::unstable_remove_test(); diff --git a/SG14_test/structured_binding_traits_test.cpp b/SG14_test/structured_binding_traits_test.cpp new file mode 100644 index 00000000..d20c72f9 --- /dev/null +++ b/SG14_test/structured_binding_traits_test.cpp @@ -0,0 +1,118 @@ +#include "SG14_test.h" +#include "structured_binding_traits.h" + +#include +#include +#include +#include +#include + +struct key_16_8_t { + uint16_t index; + uint8_t generation; +}; +struct key_11_5_t { + uint16_t index : 11; + uint8_t generation : 5; +}; +struct unique_view { + std::unique_ptr p; + int z; +}; +struct tuple_ish { + tuple_ish(int x, int y) : x(x), y(y) {} + int x, y; +}; +namespace std { template<> class tuple_size : public std::integral_constant {}; } + +template class Pred, class T, bool B> +int static_assert_predicate() +{ + static_assert(Pred::value == B, ""); + return 0; +} + +template class Pred, class... Ts> +void static_assert_true() +{ + int dummy[] = { + static_assert_predicate() ... + }; + (void)dummy; +} + +template class Pred, class... Ts> +void static_assert_false() +{ + int dummy[] = { + static_assert_predicate() ... + }; + (void)dummy; +} + +template using is_0_constructible = stdext::is_n_constructible<0, T>; +template using is_1_constructible = stdext::is_n_constructible<1, T>; +template using is_2_constructible = stdext::is_n_constructible<2, T>; +template using is_3_constructible = stdext::is_n_constructible<3, T>; + +template using is_aggregate_size_0 = std::integral_constant::value == 0>; +template using is_aggregate_size_1 = std::integral_constant::value == 1>; +template using is_aggregate_size_2 = std::integral_constant::value == 2>; + +template using is_bindable_0 = stdext::is_structured_bindable<0, T>; +template using is_bindable_1 = stdext::is_structured_bindable<1, T>; +template using is_bindable_2 = stdext::is_structured_bindable<2, T>; + +void sg14_test::structured_binding_traits_test() +{ + using A0 = int[0]; + using A1 = int[1]; + using A2 = int[2]; + using F = int(int); + using I = int; + using IP = int*; + using K2 = key_16_8_t; + using KB2 = key_11_5_t; + using KU2 = unique_view; + using SA0 = std::array; + using SA1 = std::array; + using SA2 = std::array; + using SC2 = std::complex; + using SP = std::pair; + using ST0 = std::tuple<>; + using ST1 = std::tuple; + using ST2 = std::tuple; + using SV = std::vector; + using T2 = tuple_ish; + + static_assert_true(); + static_assert_false(); + + static_assert_true(); + static_assert_false(); + + static_assert_true(); + static_assert_false(); + + static_assert_true(); + static_assert_false(); + + static_assert_true(); + static_assert_false(); + + static_assert_true(); + static_assert_true(); + + static_assert_false(); + static_assert_true(); + static_assert_false(); + static_assert_true(); + static_assert_false(); +} + +#ifdef TEST_MAIN +int main() +{ + sg14_test::structured_binding_traits_test(); +} +#endif diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 08571485..aad4f5cc 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -27,6 +27,7 @@ set(SOURCE_FILES ${SG14_TEST_SOURCE_DIRECTORY}/plf_colony_test.cpp ${SG14_TEST_SOURCE_DIRECTORY}/ring_test.cpp ${SG14_TEST_SOURCE_DIRECTORY}/slot_map_test.cpp + ${SG14_TEST_SOURCE_DIRECTORY}/structured_binding_traits_test.cpp ${SG14_TEST_SOURCE_DIRECTORY}/transcode_test.cpp ${SG14_TEST_SOURCE_DIRECTORY}/uninitialized_test.cpp ${SG14_TEST_SOURCE_DIRECTORY}/unstable_remove_test.cpp