Skip to content

Dereferencing boost::fusion::vector<>'s iterator is not SFINAE-friendly #278

@yaito3014

Description

@yaito3014

Consider following code:

#include <boost/fusion/container/vector.hpp>

#include <type_traits>

template <class Iterator, class = void>
struct is_dereferenceable : std::false_type {};

template <class Iterator>
struct is_dereferenceable<Iterator, decltype(*boost::declval<Iterator>())> : std::true_type {};

using empty_vector = boost::fusion::vector<>;
using empty_vector_iterator = boost::fusion::result_of::begin<empty_vector>::type;
static_assert(!is_dereferenceable<empty_vector_iterator>::value);

int main() {}

This code should compile successfully, guaranteeing empty_vector_iterator is never dereferenceable.
However, this emits following hard errors:

In file included from /usr/include/boost/fusion/container/vector.hpp:10,
                 from source.cpp:1:
/usr/include/boost/fusion/container/vector/detail/value_at_impl.hpp: In instantiation of ‘struct boost::fusion::extension::value_at_impl<boost::fusion::vector_tag>::apply<boost::fusion::vector<>, mpl_::int_<0> >’:
/usr/include/boost/fusion/container/vector/detail/deref_impl.hpp:33:97:   required from ‘struct boost::fusion::extension::deref_impl<boost::fusion::vector_iterator_tag>::apply<boost::fusion::vector_iterator<boost::fusion::vector<>, 0> >’
/usr/include/boost/fusion/iterator/deref.hpp:51:16:   required from ‘struct boost::fusion::result_of::deref<boost::fusion::vector_iterator<boost::fusion::vector<>, 0> >’
/usr/include/boost/fusion/iterator/deref.hpp:69:5:   required by substitution of ‘template<class Iterator> constexpr typename boost::fusion::result_of::deref<Iterator>::type boost::fusion::operator*(const iterator_base<Iterator>&) [with Iterator = boost::fusion::vector_iterator<boost::fusion::vector<>, 0>]’
source.cpp:9:46:   required by substitution of ‘template<class Iterator> struct is_dereferenceable<Iterator, decltype (* declval<Iterator>())> [with Iterator = boost::fusion::vector_iterator<boost::fusion::vector<>, 0>]’
source.cpp:13:57:   required from here
/usr/include/boost/fusion/container/vector/detail/value_at_impl.hpp:50:28: error: no matching function for call to ‘value_at_impl<mpl_::int_<0>::value>(boost::fusion::vector<>*)’
   50 |             struct apply : BOOST_FUSION_DECLTYPE_N3031((
      |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/boost/fusion/container/vector/detail/at_impl.hpp:12,
                 from /usr/include/boost/fusion/container/vector/vector.hpp:29,
                 from /usr/include/boost/fusion/container/vector.hpp:12:
/usr/include/boost/fusion/container/vector/detail/value_at_impl.hpp:38:26: note: candidate: ‘template<long unsigned int N, class U> boost::mpl::identity<U> boost::fusion::vector_detail::value_at_impl(const volatile store<N, U>*)’
   38 |         mpl::identity<U> value_at_impl(store<N, U> const volatile*);
      |                          ^~~~~~~~~~~~~
/usr/include/boost/fusion/container/vector/detail/value_at_impl.hpp:38:26: note:   template argument deduction/substitution failed:
/usr/include/boost/fusion/container/vector/detail/value_at_impl.hpp:50:28: note:   ‘boost::fusion::vector<>’ is not derived from ‘const volatile boost::fusion::vector_detail::store<0, U>’
   50 |             struct apply : BOOST_FUSION_DECLTYPE_N3031((
      |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/boost/fusion/container/vector/vector_iterator.hpp:12,
                 from /usr/include/boost/fusion/container/vector/detail/begin_impl.hpp:11,
                 from /usr/include/boost/fusion/container/vector/vector.hpp:31:
/usr/include/boost/fusion/container/vector/detail/deref_impl.hpp: In instantiation of ‘struct boost::fusion::extension::deref_impl<boost::fusion::vector_iterator_tag>::apply<boost::fusion::vector_iterator<boost::fusion::vector<>, 0> >’:
/usr/include/boost/fusion/iterator/deref.hpp:51:16:   required from ‘struct boost::fusion::result_of::deref<boost::fusion::vector_iterator<boost::fusion::vector<>, 0> >’
/usr/include/boost/fusion/iterator/deref.hpp:69:5:   required by substitution of ‘template<class Iterator> constexpr typename boost::fusion::result_of::deref<Iterator>::type boost::fusion::operator*(const iterator_base<Iterator>&) [with Iterator = boost::fusion::vector_iterator<boost::fusion::vector<>, 0>]’
source.cpp:9:46:   required by substitution of ‘template<class Iterator> struct is_dereferenceable<Iterator, decltype (* declval<Iterator>())> [with Iterator = boost::fusion::vector_iterator<boost::fusion::vector<>, 0>]’
source.cpp:13:57:   required from here
/usr/include/boost/fusion/container/vector/detail/deref_impl.hpp:33:97: error: no type named ‘type’ in ‘struct boost::fusion::extension::value_at_impl<boost::fusion::vector_tag>::apply<boost::fusion::vector<>, mpl_::int_<0> >’
   33 |                 typedef typename value_at_impl<vector_tag>::template apply<vector, index>::type element;
      |                                                                                                 ^~~~~~~
/usr/include/boost/fusion/container/vector/detail/deref_impl.hpp:41:17: error: no type named ‘type’ in ‘struct boost::fusion::extension::value_at_impl<boost::fusion::vector_tag>::apply<boost::fusion::vector<>, mpl_::int_<0> >’
   41 |                 type;
      |                 ^~~~

This breaks some existing constrained codes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions