pfr icon indicating copy to clipboard operation
pfr copied to clipboard

A limitation in c++17 mode

Open namark opened this issue 4 years ago • 0 comments

Hi, I thought of using the magic of this library as a shortcut for providing a standard "tuple-like" interface for aggregates, for use in generic code that expects it, in the following way

#include <boost/pfr.hpp>
#include <iostream>
#include <tuple>

namespace ma
{

	struct A
	{
		int a, b;
	};
	using boost::pfr::get;

}

template <> struct std::tuple_size<ma::A> :
	boost::pfr::tuple_size<ma::A> {};
template <std::size_t I> struct std::tuple_element<I, ma::A> :
	boost::pfr::tuple_element<I, ma::A> {};

int main()
{
	ma::A x{1,2};
	using std::get;
	std::cout << get<1>(x) << '\n';
}

but in c++17 mode this creates a sort of a circular dependency. As far as I understand, the pfr::get (along with pfr::tuple_element) depends on structured binding, which (since std::tuple_size is specialized) depends on ADLed get, which is the pfr::get again. The whole thing manifests as a compiler error like this on gcc 10.2

In file included from ./pfr/include/boost/pfr.hpp:12,
                 from boost_pfr.cpp:1:
./pfr/include/boost/pfr/core.hpp: In instantiation of ‘constexpr decltype(auto) boost::pfr::get(T&) [with long unsigned int I = 0; T = ma::A]’:
./pfr/include/boost/pfr/detail/core17_generated.hpp:51:10:   required from ‘constexpr auto boost::pfr::detail::tie_as_tuple(T&, boost::pfr::detail::size_t_<2>) [with T = ma::A; boost::pfr::detail::size_t_<2> = std::integral_constant<long unsigned int, 2>]’
./pfr/include/boost/pfr/detail/core17.hpp:55:42:   required from ‘constexpr auto boost::pfr::detail::tie_as_tuple(T&) [with T = ma::A]’
./pfr/include/boost/pfr/core.hpp:81:108:   required by substitution of ‘template<long unsigned int I, class T> using tuple_element = boost::pfr::detail::sequence_tuple::tuple_element<I, decltype (boost::pfr::detail::tie_as_tuple(declval<T&>()))> [with long unsigned int I = i; T = ma::A]’
boost_pfr.cpp:19:36:   required from here
./pfr/include/boost/pfr/core.hpp:54:64: error: use of ‘constexpr auto boost::pfr::detail::tie_as_tuple(T&) [with T = ma::A]’ before deduction of ‘auto’
   54 |     return detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) );
      |                                            ~~~~~~~~~~~~~~~~~~~~^~~~~
In file included from ./pfr/include/boost/pfr/detail/core17.hpp:10,
                 from ./pfr/include/boost/pfr/detail/core.hpp:17,
                 from ./pfr/include/boost/pfr/core.hpp:12,
                 from ./pfr/include/boost/pfr.hpp:12,
                 from boost_pfr.cpp:1:
./pfr/include/boost/pfr/detail/core17_generated.hpp: In instantiation of ‘constexpr auto boost::pfr::detail::tie_as_tuple(T&, boost::pfr::detail::size_t_<2>) [with T = ma::A; boost::pfr::detail::size_t_<2> = std::integral_constant<long unsigned int, 2>]’:
./pfr/include/boost/pfr/detail/core17.hpp:55:42:   required from ‘constexpr auto boost::pfr::detail::tie_as_tuple(T&) [with T = ma::A]’
./pfr/include/boost/pfr/core.hpp:81:108:   required by substitution of ‘template<long unsigned int I, class T> using tuple_element = boost::pfr::detail::sequence_tuple::tuple_element<I, decltype (boost::pfr::detail::tie_as_tuple(declval<T&>()))> [with long unsigned int I = i; T = ma::A]’
boost_pfr.cpp:19:36:   required from here
./pfr/include/boost/pfr/detail/core17_generated.hpp:51:10: note: in initialization of structured binding variable ‘a’
   51 |   auto& [a,b] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
      |          ^

I guess this kind of usage is somewhat out of scope of the library, but it seems to work fine with BOOST_PFR_USE_CPP17 defined as 0.

namark avatar Apr 19 '21 16:04 namark