boostorg / pfr

std::tuple like methods for user defined types without any macro or boilerplate code
https://boost.org/libs/pfr
Boost Software License 1.0
1.33k stars 159 forks source link

Errors for classes with empty base(s), C++17 #36

Open zmij opened 5 years ago

zmij commented 5 years ago

Provided the following hierarchy of classes:

namespace empty_base {

struct A {};
struct B {};

// Empty base, no members
struct C : A {};
// Empty base, some members
struct D : A { double d; };
// Two empty bases, no members
struct E : A, B {};
// Two empty bases, some membes
struct F : A, B { float f; };

}

When trying to use pfr with them there are the following errors (the error messages are somewhat shortened):

Class with an empty base and no members Precise:

> decltype(structure_to_tuple(declval<empty_base::C>()))
./include/boost/pfr/detail/core17_generated.hpp:39:9: fatal error: type 'const empty_base::C' decomposes into 0 elements, but 1 names were provided
  auto& [a] = val;
        ^
./include/boost/pfr/detail/core17_generated.hpp:1037:30: note: in instantiation of function template specialization 'boost::pfr::detail::tie_as_tuple<const empty_base::C>' requested here
  return boost::pfr::detail::tie_as_tuple(val, fields_count_tag{});
                             ^
./include/boost/pfr/precise/core.hpp:93:17: note: in instantiation of function template specialization 'boost::pfr::detail::tie_as_tuple<const empty_base::C>' requested here
        detail::tie_as_tuple(val),

Flat:

> decltype(flat_structure_to_tuple(declval<empty_base::C>()))
std::tuple<> // This is fine, actually

Class with an empty base and some members Presize:

> decltype(structure_to_tuple(declval<empty_base::D>()))
./include/boost/pfr/detail/core17_generated.hpp:52:9: fatal error: type 'const empty_base::D' decomposes into 1 elements, but 2 names were provided
  auto& [a,b] = val;
        ^
./include/boost/pfr/detail/core17_generated.hpp:1037:30: note: in instantiation of function template specialization 'boost::pfr::detail::tie_as_tuple<const empty_base::D>' requested here
  return boost::pfr::detail::tie_as_tuple(val, fields_count_tag{});
                             ^
./include/boost/pfr/precise/core.hpp:93:17: note: in instantiation of function template specialization 'boost::pfr::detail::tie_as_tuple<const empty_base::D>' requested here
        detail::tie_as_tuple(val)

Flat:

> decltype(flat_structure_to_tuple(declval<empty_base::D>()))
./include/boost/pfr/detail/offset_based_getter.hpp:63:3: fatal error: static_assert failed "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!"
  static_assert(sizeof(U) == sizeof(S), "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!");
// Nice assert, but doesn't help, actually

Class with two empty bases and no members Precise:

> decltype(structure_to_tuple(declval<empty_base::E>()))
./include/boost/pfr/detail/core17_generated.hpp:52:9: fatal error: type 'const empty_base::E' decomposes into 0 elements, but 2 names were provided
  auto& [a,b] = val;

Flat:

> decltype(flat_structure_to_tuple(declval<empty_base::E>()))
./include/boost/pfr/detail/offset_based_getter.hpp:63:3: fatal error: static_assert failed "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!"
  static_assert(sizeof(U) == sizeof(S), "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!");

Class with two empty bases and some members Precise:

> decltype(structure_to_tuple(declval<empty_base::F>()))
./include/boost/pfr/detail/core17_generated.hpp:58:9: fatal error: type 'const empty_base::F' decomposes into 1 elements, but 3 names were provided
  auto& [a,b,c] = val;

Flat:

> decltype(flat_structure_to_tuple(declval<empty_base::F>()))
./include/boost/pfr/detail/offset_based_getter.hpp:63:3: fatal error: static_assert failed "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!"
  static_assert(sizeof(U) == sizeof(S), "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!");
hadrielk commented 4 years ago

I got the same issue with a class that derives from a CRTP-based empty base class. (boost::orable in my case, from boost operators)

I'm just noting it so that CRTP-bases are added as a test, if/when this issue is fixed. (CRTP empty bases are fairly common, I think)

apolukhin commented 3 years ago

The diagnostic was added in https://github.com/boostorg/pfr/commit/180db174ad5543577e525ca230974a98fac13004#diff-9f25dfaeef0127087c5ed7f25def6deb967c8b1cef9427801f07782652a0044d and https://github.com/boostorg/pfr/commit/ea4c6e85f734b0ed9f4233ba9654b877398fa948#diff-9f25dfaeef0127087c5ed7f25def6deb967c8b1cef9427801f07782652a0044d

Will merge to master after 1.76 release