Extracted enable_if_convertible trait to a separate header.

Keep including the new header in iterator_adaptor.hpp for backward
compatibility, until downstream users are updated to include the new
header.
This commit is contained in:
Andrey Semashev 2025-02-04 00:53:37 +03:00
parent c22af90b60
commit cb81a1dfc3
9 changed files with 94 additions and 63 deletions

View File

@ -0,0 +1,84 @@
/*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* https://www.boost.org/LICENSE_1_0.txt)
*
* Copyright (c) 2025 Andrey Semashev
*/
#ifndef BOOST_ITERATOR_ENABLE_IF_CONVERTIBLE_HPP_INCLUDED_
#define BOOST_ITERATOR_ENABLE_IF_CONVERTIBLE_HPP_INCLUDED_
#include <type_traits>
namespace boost {
namespace iterators {
namespace detail {
//
// Result type used in enable_if_convertible meta function.
// This can be an incomplete type, as only pointers to
// enable_if_convertible< ... >::type are used.
// We could have used void for this, but conversion to
// void* is just too easy.
//
struct enable_type;
} // namespace detail
//
// enable_if for use in adapted iterators constructors.
//
// In order to provide interoperability between adapted constant and
// mutable iterators, adapted iterators will usually provide templated
// conversion constructors of the following form
//
// template <class BaseIterator>
// class adapted_iterator :
// public iterator_adaptor< adapted_iterator<Iterator>, Iterator >
// {
// public:
//
// ...
//
// template <class OtherIterator>
// adapted_iterator(
// OtherIterator const& it
// , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0);
//
// ...
// };
//
// enable_if_convertible is used to remove those overloads from the overload
// set that cannot be instantiated. For all practical purposes only overloads
// for constant/mutable interaction will remain. This has the advantage that
// meta functions like boost::is_convertible do not return false positives,
// as they can only look at the signature of the conversion constructor
// and not at the actual instantiation.
//
// enable_if_interoperable can be safely used in user code. It falls back to
// always enabled for compilers that don't support enable_if or is_convertible.
// There is no need for compiler specific workarounds in user code.
//
// The operators implementation relies on boost::is_convertible not returning
// false positives for user/library defined iterator types. See comments
// on operator implementation for consequences.
//
template< typename From, typename To >
struct enable_if_convertible :
public std::enable_if<
std::is_convertible< From, To >::value,
boost::iterators::detail::enable_type
>
{};
template< typename From, typename To >
using enable_if_convertible_t = typename enable_if_convertible< From, To >::type;
} // namespace iterators
using iterators::enable_if_convertible;
} // namespace boost
#endif // BOOST_ITERATOR_ENABLE_IF_CONVERTIBLE_HPP_INCLUDED_

View File

@ -11,6 +11,7 @@
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/iterator/enable_if_convertible.hpp>
#include <boost/core/use_default.hpp>
namespace boost {

View File

@ -11,6 +11,7 @@
#include <type_traits>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/enable_if_convertible.hpp>
#include <boost/pointee.hpp>
#include <boost/indirect_reference.hpp>
@ -84,7 +85,7 @@ public:
typename Category2,
typename Reference2,
typename Difference2,
typename = typename enable_if_convertible< Iterator2, Iterator >::type
typename = enable_if_convertible_t< Iterator2, Iterator >
>
indirect_iterator(indirect_iterator< Iterator2, Value2, Category2, Reference2, Difference2 > const& y) :
super_t(y.base())

View File

@ -14,6 +14,7 @@
#include <boost/iterator/iterator_categories.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/iterator/iterator_traits.hpp>
#include <boost/iterator/enable_if_convertible.hpp> // for backward compatibility; remove once downstream users are updated
#include <boost/iterator/detail/config_def.hpp>
@ -25,65 +26,6 @@ namespace iterators {
// explicitly in order to specify that the default should be used.
using boost::use_default;
namespace detail {
//
// Result type used in enable_if_convertible meta function.
// This can be an incomplete type, as only pointers to
// enable_if_convertible< ... >::type are used.
// We could have used void for this, but conversion to
// void* is just too easy.
//
struct enable_type;
} // namespace detail
//
// enable_if for use in adapted iterators constructors.
//
// In order to provide interoperability between adapted constant and
// mutable iterators, adapted iterators will usually provide templated
// conversion constructors of the following form
//
// template <class BaseIterator>
// class adapted_iterator :
// public iterator_adaptor< adapted_iterator<Iterator>, Iterator >
// {
// public:
//
// ...
//
// template <class OtherIterator>
// adapted_iterator(
// OtherIterator const& it
// , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0);
//
// ...
// };
//
// enable_if_convertible is used to remove those overloads from the overload
// set that cannot be instantiated. For all practical purposes only overloads
// for constant/mutable interaction will remain. This has the advantage that
// meta functions like boost::is_convertible do not return false positives,
// as they can only look at the signature of the conversion constructor
// and not at the actual instantiation.
//
// enable_if_interoperable can be safely used in user code. It falls back to
// always enabled for compilers that don't support enable_if or is_convertible.
// There is no need for compiler specific workarounds in user code.
//
// The operators implementation relies on boost::is_convertible not returning
// false positives for user/library defined iterator types. See comments
// on operator implementation for consequences.
//
template< typename From, typename To >
struct enable_if_convertible :
public std::enable_if<
std::is_convertible< From, To >::value,
boost::iterators::detail::enable_type
>
{};
//
// Default template argument handling for iterator_adaptor
//
@ -297,7 +239,6 @@ private: // data members
} // namespace iterators
using iterators::iterator_adaptor;
using iterators::enable_if_convertible;
} // namespace boost

View File

@ -12,7 +12,7 @@
#include <boost/core/use_default.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/enable_if_convertible.hpp>
namespace boost {
namespace iterators {

View File

@ -8,6 +8,7 @@
#define BOOST_REVERSE_ITERATOR_23022003THW_HPP
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/enable_if_convertible.hpp>
namespace boost {
namespace iterators {

View File

@ -12,6 +12,8 @@
#include <boost/core/use_default.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/iterator/enable_if_convertible.hpp>
#include <boost/utility/result_of.hpp>
#include <type_traits>

View File

@ -10,7 +10,7 @@
#include <boost/iterator/iterator_traits.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/iterator/iterator_adaptor.hpp> // for enable_if_convertible
#include <boost/iterator/enable_if_convertible.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/iterator/minimum_category.hpp>

View File

@ -15,6 +15,7 @@
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/is_readable_iterator.hpp>
#include <boost/iterator/is_lvalue_iterator.hpp>
#include <boost/iterator/enable_if_convertible.hpp>
#include <boost/pending/iterator_tests.hpp>
# include <boost/core/lightweight_test.hpp>