%PDF- %PDF-
Direktori : /backups/router/usr/local/include/boost/pfr/detail/ |
Current File : //backups/router/usr/local/include/boost/pfr/detail/core14_loophole.hpp |
// Copyright (c) 2017-2018 Alexandr Poltavsky, Antony Polukhin. // Copyright (c) 2019-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) // The Great Type Loophole (C++14) // Initial implementation by Alexandr Poltavsky, http://alexpolt.github.io // // Description: // The Great Type Loophole is a technique that allows to exchange type information with template // instantiations. Basically you can assign and read type information during compile time. // Here it is used to detect data members of a data type. I described it for the first time in // this blog post http://alexpolt.github.io/type-loophole.html . // // This technique exploits the http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118 // CWG 2118. Stateful metaprogramming via friend injection // Note: CWG agreed that such techniques should be ill-formed, although the mechanism for prohibiting them is as yet undetermined. #ifndef BOOST_PFR_DETAIL_CORE14_LOOPHOLE_HPP #define BOOST_PFR_DETAIL_CORE14_LOOPHOLE_HPP #pragma once #include <boost/pfr/detail/config.hpp> #include <type_traits> #include <utility> #include <boost/pfr/detail/offset_based_getter.hpp> #include <boost/pfr/detail/fields_count.hpp> #include <boost/pfr/detail/make_flat_tuple_of_references.hpp> #include <boost/pfr/detail/make_integer_sequence.hpp> #include <boost/pfr/detail/sequence_tuple.hpp> #include <boost/pfr/detail/rvalue_t.hpp> #include <boost/pfr/detail/unsafe_declval.hpp> #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wmissing-braces" # pragma clang diagnostic ignored "-Wundefined-inline" # pragma clang diagnostic ignored "-Wundefined-internal" # pragma clang diagnostic ignored "-Wmissing-field-initializers" #elif defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wnon-template-friend" #endif namespace boost { namespace pfr { namespace detail { // tag<T,N> generates friend declarations and helps with overload resolution. // There are two types: one with the auto return type, which is the way we read types later. // The second one is used in the detection of instantiations without which we'd get multiple // definitions. template <class T, std::size_t N> struct tag { friend auto loophole(tag<T,N>); }; // The definitions of friend functions. template <class T, class U, std::size_t N, bool B> struct fn_def_lref { friend auto loophole(tag<T,N>) { // Standard Library containers do not SFINAE on invalid copy constructor. Because of that std::vector<std::unique_ptr<int>> reports that it is copyable, // which leads to an instantiation error at this place. // // To workaround the issue, we check that the type U is movable, and move it in that case. using no_extents_t = std::remove_all_extents_t<U>; return static_cast< std::conditional_t<std::is_move_constructible<no_extents_t>::value, no_extents_t&&, no_extents_t&> >( boost::pfr::detail::unsafe_declval<no_extents_t&>() ); } }; template <class T, class U, std::size_t N, bool B> struct fn_def_rref { friend auto loophole(tag<T,N>) { return std::move(boost::pfr::detail::unsafe_declval< std::remove_all_extents_t<U>& >()); } }; // Those specializations are to avoid multiple definition errors. template <class T, class U, std::size_t N> struct fn_def_lref<T, U, N, true> {}; template <class T, class U, std::size_t N> struct fn_def_rref<T, U, N, true> {}; // This has a templated conversion operator which in turn triggers instantiations. // Important point, using sizeof seems to be more reliable. Also default template // arguments are "cached" (I think). To fix that I provide a U template parameter to // the ins functions which do the detection using constexpr friend functions and SFINAE. template <class T, std::size_t N> struct loophole_ubiq_lref { template<class U, std::size_t M> static std::size_t ins(...); template<class U, std::size_t M, std::size_t = sizeof(loophole(tag<T,M>{})) > static char ins(int); template<class U, std::size_t = sizeof(fn_def_lref<T, U, N, sizeof(ins<U, N>(0)) == sizeof(char)>)> constexpr operator U&() const&& noexcept; // `const&&` here helps to avoid ambiguity in loophole instantiations. optional_like test validate that behavior. }; template <class T, std::size_t N> struct loophole_ubiq_rref { template<class U, std::size_t M> static std::size_t ins(...); template<class U, std::size_t M, std::size_t = sizeof(loophole(tag<T,M>{})) > static char ins(int); template<class U, std::size_t = sizeof(fn_def_rref<T, U, N, sizeof(ins<U, N>(0)) == sizeof(char)>)> constexpr operator U&&() const&& noexcept; // `const&&` here helps to avoid ambiguity in loophole instantiations. optional_like test validate that behavior. }; // This is a helper to turn a data structure into a tuple. template <class T, class U> struct loophole_type_list_lref; template <typename T, std::size_t... I> struct loophole_type_list_lref< T, std::index_sequence<I...> > // Instantiating loopholes: : sequence_tuple::tuple< decltype(T{ loophole_ubiq_lref<T, I>{}... }, 0) > { using type = sequence_tuple::tuple< decltype(loophole(tag<T, I>{}))... >; }; template <class T, class U> struct loophole_type_list_rref; template <typename T, std::size_t... I> struct loophole_type_list_rref< T, std::index_sequence<I...> > // Instantiating loopholes: : sequence_tuple::tuple< decltype(T{ loophole_ubiq_rref<T, I>{}... }, 0) > { using type = sequence_tuple::tuple< decltype(loophole(tag<T, I>{}))... >; }; // Lazily returns loophole_type_list_{lr}ref. template <bool IsCopyConstructible /*= true*/, class T, class U> struct loophole_type_list_selector { using type = loophole_type_list_lref<T, U>; }; template <class T, class U> struct loophole_type_list_selector<false /*IsCopyConstructible*/, T, U> { using type = loophole_type_list_rref<T, U>; }; template <class T> auto tie_as_tuple_loophole_impl(T& lvalue) noexcept { using type = std::remove_cv_t<std::remove_reference_t<T>>; using indexes = detail::make_index_sequence<fields_count<type>()>; using loophole_type_list = typename detail::loophole_type_list_selector< std::is_copy_constructible<std::remove_all_extents_t<type>>::value, type, indexes >::type; using tuple_type = typename loophole_type_list::type; return boost::pfr::detail::make_flat_tuple_of_references( lvalue, offset_based_getter<type, tuple_type>{}, size_t_<0>{}, size_t_<tuple_type::size_v>{} ); } template <class T> auto tie_as_tuple(T& val) noexcept { static_assert( !std::is_union<T>::value, "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info." ); return boost::pfr::detail::tie_as_tuple_loophole_impl( val ); } template <class T, class F, std::size_t... I> void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) { static_assert( !std::is_union<T>::value, "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info." ); std::forward<F>(f)( boost::pfr::detail::tie_as_tuple_loophole_impl(t) ); } }}} // namespace boost::pfr::detail #ifdef __clang__ # pragma clang diagnostic pop #elif defined(__GNUC__) # pragma GCC diagnostic pop #endif #endif // BOOST_PFR_DETAIL_CORE14_LOOPHOLE_HPP