Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions include/boost/pfr/detail/possible_reflectable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,23 @@
#include <boost/pfr/traits_fwd.hpp>

#if !defined(BOOST_PFR_INTERFACE_UNIT)
#include <array> // for std::array
#include <cstddef> // for std::size_t
#include <type_traits> // for std::is_aggregate
#endif

namespace boost { namespace pfr { namespace detail {

// std::array<T, N> is an aggregate, but it stores its elements in a C array

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workaround is too specific... How about treating all the types with name array (std::array, boost::array, ...) as non reflectable?

This could be done in the following way:

template <class T>
constexpr std::false_type is_array(int);

template <class T>
constexpr auto is_array(long) -> decltype(std::declval<T>().~array(), std::true_type{});

Call it as decltype(detail::is_array<T>(1L))::value

That way there's no need to include <array> and it would work with boost::array too

// data member. Boost.PFR can not reflect types with C array members yet (see
// https://github.com/boostorg/pfr/issues/20), so std::array must not be
// treated as implicitly reflectable.
template <class T>
struct is_stdarray : std::false_type {};

template <class T, std::size_t N>
struct is_stdarray<std::array<T, N>> : std::true_type {};

///////////////////// Returns false when the type exactly wasn't be reflectable
template <class T, class WhatFor>
constexpr decltype(is_reflectable<T, WhatFor>::value) possible_reflectable(long) noexcept {
Expand All @@ -26,11 +38,11 @@ constexpr decltype(is_reflectable<T, WhatFor>::value) possible_reflectable(long)

template <class T, class WhatFor>
constexpr bool possible_reflectable(int) noexcept {
# if defined(__cpp_lib_is_aggregate)
using type = std::remove_cv_t<T>;
return std::is_aggregate<type>();
# if defined(__cpp_lib_is_aggregate)
return std::is_aggregate<type>() && !detail::is_stdarray<type>::value;
# else
return true;
return !detail::is_stdarray<type>::value;
# endif
}

Expand Down
11 changes: 11 additions & 0 deletions test/core/run/is_implicitly_reflectable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// 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 <array>
#include <iostream>
#include <boost/pfr/traits.hpp>
#include <type_traits> // for std::true_type, std::false_type and std::is_aggregate
Expand Down Expand Up @@ -71,6 +72,12 @@ int main() {
assert_non_reflectable<Nonrefrectable, tag>();
assert_reflectable<ReflectableBoostJson, tag>();
assert_non_reflectable<NonrefrectableBoostJson, tag>();

// std::array is an aggregate, but it holds a C array member that
// Boost.PFR can not reflect correctly, so it must not be considered
// implicitly reflectable (https://github.com/boostorg/pfr/issues/169).
assert_non_reflectable<std::array<int, 3>, tag>();
assert_non_reflectable<std::array<char, 1>, tag>();
}

{
Expand All @@ -81,6 +88,10 @@ int main() {
assert_non_reflectable<Nonrefrectable, tag>();
assert_reflectable<ReflectableBoostFusion, tag>();
assert_non_reflectable<NonrefrectableBoostFusion, tag>();

// See the comment in the boost_json_tag block above.
assert_non_reflectable<std::array<int, 3>, tag>();
assert_non_reflectable<std::array<char, 1>, tag>();
}
#endif // #if BOOST_PFR_ENABLE_IMPLICIT_REFLECTION
}
Expand Down
Loading