2
0
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:
Antony Polukhin
2019-01-05 13:42:27 +03:00
committed by GitHub
6 changed files with 106 additions and 18 deletions

View File

@@ -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

View File

@@ -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,

View File

@@ -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 ]

View File

@@ -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();
}

View File

@@ -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
View 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();
}