mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-19 04:22:13 +00:00
Merge pull request #32 from apolukhin/feature/reflecting-unique
Fixes #30
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2017 Antony Polukhin
|
||||
// Copyright (c) 2016-2019 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)
|
||||
@@ -39,6 +39,8 @@
|
||||
// Assume that libstdc++ since GCC-7.3 does not have linear instantiation depth in std::make_integral_sequence
|
||||
# if defined( __GLIBCXX__) && __GLIBCXX__ >= 20180101
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1
|
||||
# elif defined(_MSC_VER)
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1
|
||||
//# elif other known working lib
|
||||
# else
|
||||
# define BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 0
|
||||
|
||||
@@ -66,13 +66,21 @@ template <class T> constexpr T& unsafe_declval_like() noexcept {
|
||||
|
||||
// The definitions of friend functions.
|
||||
template <class T, class U, std::size_t N, bool B>
|
||||
struct fn_def {
|
||||
struct fn_def_lref {
|
||||
friend auto loophole(tag<T,N>) { return boost::pfr::detail::unsafe_declval_like< std::remove_all_extents_t<U> >(); }
|
||||
};
|
||||
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_like< std::remove_all_extents_t<U> >()); }
|
||||
};
|
||||
|
||||
// This specialization is to avoid multiple definition errors.
|
||||
|
||||
// Those specializations are to avoid multiple definition errors.
|
||||
template <class T, class U, std::size_t N>
|
||||
struct fn_def<T, U, N, true> {};
|
||||
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.
|
||||
@@ -80,33 +88,68 @@ struct fn_def<T, U, N, true> {};
|
||||
// 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 {
|
||||
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<T, U, N, sizeof(ins<U, N>(0)) == sizeof(char)>)>
|
||||
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;
|
||||
struct loophole_type_list_lref;
|
||||
|
||||
template <typename T, std::size_t... I>
|
||||
struct loophole_type_list< T, std::index_sequence<I...> >
|
||||
struct loophole_type_list_lref< T, std::index_sequence<I...> >
|
||||
// Instantiating loopholes:
|
||||
: sequence_tuple::tuple< decltype(T{ loophole_ubiq<T, I>{}... }, 0) >
|
||||
: 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 tuple_type = typename loophole_type_list<type, indexes>::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,
|
||||
|
||||
@@ -95,14 +95,14 @@ test-suite pfr
|
||||
[ run common/non_default_constructible.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_default_constructible ]
|
||||
|
||||
[ compile-fail common/non_copyable_but_movable.cpp : $(CLASSIC_FLAT_DEF) : flat_non_copyable_but_movable ]
|
||||
[ compile-fail common/non_copyable_but_movable.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_copyable_but_movable ]
|
||||
[ run common/non_copyable_but_movable.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_copyable_but_movable ]
|
||||
[ run common/non_copyable_but_movable.cpp : : : $(CLASSIC_PREC_DEF) : precise_non_copyable_but_movable ]
|
||||
[ run common/non_copyable_but_movable.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_copyable_but_movable ]
|
||||
|
||||
[ compile-fail common/non_default_constructible_non_copyable_but_movable.cpp : $(CLASSIC_FLAT_DEF) : flat_non_dc_non_cop_but_movable ]
|
||||
[ compile-fail common/non_default_constructible_non_copyable_but_movable.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_dc_non_cop_but_movable ]
|
||||
[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(CLASSIC_PREC_DEF) : precise_non_dc_non_cop_but_movable ]
|
||||
[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_dc_non_cop_but_movable ]
|
||||
[ compile-fail common/non_default_constructible_non_copyable_but_movable.cpp : $(CLASSIC_FLAT_DEF) : flat_non_dc_non_cop_but_mov ]
|
||||
[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_dc_non_cop_but_mov ]
|
||||
[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(CLASSIC_PREC_DEF) : precise_non_dc_non_cop_but_mov ]
|
||||
[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_dc_non_cop_but_mov ]
|
||||
|
||||
[ compile-fail common/fields_count_on_reference.cpp ]
|
||||
[ run common/fields_count_on_const.cpp ]
|
||||
@@ -139,6 +139,9 @@ test-suite pfr
|
||||
[ run precise/error_pfr_c1202.cpp : : : $(CLASSIC_PREC_DEF) : precise_c1202_issue21 ]
|
||||
[ compile-fail precise/non_aggregate.cpp : $(CLASSIC_PREC_DEF) : precise_non_aggregate ]
|
||||
|
||||
# This test may compile of fail depending on C++ Standard version.
|
||||
#[ compile-fail precise/issue30.cpp : : : $(CLASSIC_PREC_DEF) : precise_issue30 ]
|
||||
|
||||
|
||||
##### Loophole tests running precise and flat specific tests
|
||||
[ run flat/core.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_core ]
|
||||
@@ -156,7 +159,8 @@ test-suite pfr
|
||||
[ run precise/motivating_example2.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_motivating_example2 ]
|
||||
[ run precise/optional_like.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_optional_like ]
|
||||
[ run precise/get_non_default_constructible.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_get_non_default_constructible ]
|
||||
[ run precise/error_pfr_c1202.cpp : : : $(CLASSIC_PREC_DEF) : precise_lh_c1202_issue21 ]
|
||||
[ run precise/error_pfr_c1202.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_c1202_issue21 ]
|
||||
[ run precise/issue30.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_issue30 ]
|
||||
[ compile-fail precise/non_aggregate.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_non_aggregate ]
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
# error Misused test
|
||||
#endif
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
struct X {
|
||||
X() = default;
|
||||
X(X&&) = default;
|
||||
@@ -43,7 +45,9 @@ int main() {
|
||||
struct S6 { X x0; X x1; X x2; X x3; X x4; X x5;};
|
||||
static_assert(boost::pfr::tuple_size_v<S6> == 6, "");
|
||||
#elif defined(BOOST_PFR_TEST_FLAT)
|
||||
return boost::pfr::flat_tuple_size_v<S>;
|
||||
BOOST_TEST_EQ(boost::pfr::flat_tuple_size_v<S>, 1); // Empty structs are discarded
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
# error Misused test
|
||||
#endif
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
struct X {
|
||||
X() = delete;
|
||||
X(X&&) = default;
|
||||
@@ -43,7 +45,9 @@ int main() {
|
||||
struct S6 { X x0; X x1; X x2; X x3; X x4; X x5;};
|
||||
static_assert(boost::pfr::tuple_size_v<S6> == 6, "");
|
||||
#elif defined(BOOST_PFR_TEST_FLAT)
|
||||
return boost::pfr::flat_tuple_size_v<S>;
|
||||
BOOST_TEST_EQ(boost::pfr::flat_tuple_size_v<S>, 1); // Empty structs are discarded
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
31
test/precise/issue30.cpp
Normal file
31
test/precise/issue30.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2018-2019 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)
|
||||
|
||||
// Test case for https://github.com/apolukhin/magic_get/issues/30
|
||||
|
||||
#include <memory>
|
||||
#include <boost/pfr.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
struct Message {
|
||||
std::unique_ptr<int> data;
|
||||
};
|
||||
|
||||
struct Message2 {
|
||||
std::unique_ptr<int> data41 = std::make_unique<int>(41);
|
||||
std::unique_ptr<int> data42 = std::make_unique<int>(42);
|
||||
};
|
||||
|
||||
int main() {
|
||||
Message message;
|
||||
auto& ptr = boost::pfr::get<0>(message);
|
||||
BOOST_TEST(ptr == nullptr);
|
||||
|
||||
Message2 message2;
|
||||
auto& ptr2 = boost::pfr::get<1>(message2);
|
||||
BOOST_TEST_EQ(*ptr2, 42);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
Reference in New Issue
Block a user