Opened 6 years ago

Last modified 6 years ago

#12754 new Bugs

operator| overload for boost::range_details::replace_holder is not SFINAE friendly

Reported by: Tim Wynants <tim.wynants+boost@…> Owned by: Neil Groves
Milestone: To Be Determined Component: range
Version: Boost 1.61.0 Severity: Problem
Keywords: SFINAE, ADL, range Cc:

Description

If I provide a simple operator | overload for my template class and I provide a class template specializations with for instance a boost range (so that adl adds the boost::range_details namespace for overloads) then the compiler chokes on the non-SFINEA friendly overload

friendly boost::range_details::operator|(
    SinglePassRange,  
    const replace_holder<BOOST_DEDUCED_TYPENAME range_value<SinglePassRange>::type> )

Example:

namespace local
{
    template<typename T>
    struct boo {};

    // this overload is not prefered when T is a boost::range::xxx_range
    template<typename T, typename U>
    auto operator|(boo<T>, U)
    {
        return false;
    }

    void finds_local_operator_overload()
    {
        std::vector<int> xs;

        // works like expected and calls local::operator|
        auto f = boo<decltype(xs)>{} | xs;
    }

    void prefers_boost_range_detail_replaced_operator_overload_instead_of_local_operator()
    {
        std::vector<int> xs;
        // compiler error because it tries to call 'boost::range_detail::operator|'
        auto filtered = xs | boost::adaptors::filtered([](auto &&x){ return x % 2; });
        auto f = boo<decltype(filtered)>{} | xs;
    }
}

clang error (msvc reports almost the same):

/xxx/../../thirdparty/boost/1.60.0/dist/boost/range/value_type.hpp:26:70: error: no type named 'type' in
      'boost::range_iterator<local::boo<boost::range_detail::filtered_range<(lambda at
      /xxx/Tests.cpp:221:49), std::vector<int, std::allocator<int> > > >, void>'
    struct range_value : iterator_value< typename range_iterator<T>::type >
                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
/xxx/../../thirdparty/boost/1.60.0/dist/boost/range/adaptor/replaced.hpp:122:40: note: in instantiation of template class
      'boost::range_value<local::boo<boost::range_detail::filtered_range<(lambda at
      /xxx/Tests.cpp:221:49), std::vector<int, std::allocator<int> > > > >' requested
      here
               BOOST_DEDUCED_TYPENAME range_value<SinglePassRange>::type>& f)
                                       ^
/xxx/Tests.cpp:222:37: note: while substituting deduced template arguments into
      function template 'operator|' [with SinglePassRange = local::boo<boost::range_detail::filtered_range<(lambda at
      /xxx/Tests.cpp:221:49), std::vector<int, std::allocator<int> > > >]
        auto f = boo<decltype(filtered)>{} | xs;

This can be easily prevented by making the operator overload SFINEA friendly.

Change History (3)

comment:1 by Tim Wynants <tim.wynants+boost@…>, 6 years ago

Keywords: range added

comment:2 by Kohei Takahashi, 6 years ago

off topic: not SFINEA but SFINAE (Substitution Failure Is Not An Error).

comment:3 by Tim Wynants <tim.wynants+boost@…>, 6 years ago

Keywords: SFINAE added; SFINEA removed
Summary: operator| overload for boost::range_details::replace_holder is not SFINEA friendlyoperator| overload for boost::range_details::replace_holder is not SFINAE friendly
Note: See TracTickets for help on using tickets.