Extracted min_category as a variadic metafunction.

The new min_category is similar to minimum_category but accepts variable
number of iterator categories on input instead of just two, and also does
not depend on Boost.MPL for lambda placeholders. The existing minimum_category
trait has been reimplemented in terms of min_category and deprecated.

We don't yet emit deprecation warnings as there is still code that uses
the old trait which we first need to update. Eventually, minimum_category
will emit warnings and will be removed.
This commit is contained in:
Andrey Semashev 2025-01-27 00:04:13 +03:00
parent b30cbf634c
commit dec7d0f24c
8 changed files with 165 additions and 45 deletions

View File

@ -48,14 +48,14 @@ information is needed, call on `indirect_reference`.
Both of these templates are essential to the correct functioning of
[link iterator.specialized.indirect `indirect_iterator`].
[h2 `minimum_category`]
[h2 `min_category`]
`minimum_category` takes two iterator categories or two iterator traversal tags
`min_category` takes one or more iterator categories or iterator traversal tags
and returns the one that is the weakest (i.e. least advanced). For example:
static_assert(
is_same<
minimum_category<
min_category<
std::forward_iterator_tag,
std::random_access_iterator_tag
>::type,

View File

@ -0,0 +1,83 @@
// Copyright Andrey Semashev 2025.
//
// 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)
#ifndef BOOST_ITERATOR_MIN_CATEGORY_HPP_INCLUDED_
#define BOOST_ITERATOR_MIN_CATEGORY_HPP_INCLUDED_
#include <type_traits>
namespace boost {
namespace iterators {
namespace detail {
template<
typename T1,
typename T2,
bool GreaterEqual = std::is_convertible< T1, T2 >::value,
bool LessEqual = std::is_convertible< T2, T1 >::value
>
struct min_category_impl
{
static_assert(GreaterEqual || LessEqual, "Iterator category types must be related through convertibility.");
};
template< typename T1, typename T2 >
struct min_category_impl< T1, T2, true, false >
{
using type = T2;
};
template< typename T1, typename T2 >
struct min_category_impl< T1, T2, false, true >
{
using type = T1;
};
template< typename T1, typename T2 >
struct min_category_impl< T1, T2, true, true >
{
static_assert(std::is_same< T1, T2 >::value, "Iterator category types must be the same when they are equivalent.");
using type = T1;
};
} // namespace detail
//
// Returns the minimum iterator category type in the list
// or fails to compile if any of the categories are unrelated.
//
template< typename... Categories >
struct min_category;
template< typename T >
struct min_category< T >
{
using type = T;
};
template< typename T1, typename T2, typename... Tail >
struct min_category< T1, T2, Tail... >
{
using type = typename min_category<
typename iterators::detail::min_category_impl< T1, T2 >::type,
Tail...
>::type;
};
// Shortcut to slightly optimize compilation speed
template< typename T1, typename T2 >
struct min_category< T1, T2 >
{
using type = typename iterators::detail::min_category_impl< T1, T2 >::type;
};
template< typename... Categories >
using min_category_t = typename min_category< Categories... >::type;
} // namespace iterators
} // namespace boost
#endif // BOOST_ITERATOR_MIN_CATEGORY_HPP_INCLUDED_

View File

@ -4,61 +4,26 @@
#ifndef BOOST_ITERATOR_MINIMUM_CATEGORY_HPP_INCLUDED_
#define BOOST_ITERATOR_MINIMUM_CATEGORY_HPP_INCLUDED_
#include <type_traits>
#include <boost/mpl/arg_fwd.hpp>
#include <boost/iterator/min_category.hpp>
namespace boost {
namespace iterators {
namespace detail {
template <class T1, class T2, bool GreaterEqual, bool LessEqual>
struct minimum_category_impl;
template <class T1, class T2>
struct minimum_category_impl<T1, T2, true, false>
{
using type = T2;
};
template <class T1, class T2>
struct minimum_category_impl<T1, T2, false, true>
{
using type = T1;
};
template <class T1, class T2>
struct minimum_category_impl<T1, T2, true, true>
{
static_assert(std::is_same<T1, T2>::value, "Iterator category types must be the same when they are equivalent.");
using type = T1;
};
} // namespace detail
//
// Returns the minimum category type or fails to compile
// if T1 and T2 are unrelated.
//
// Deprecated metafunction for selecting minimum iterator category,
// use min_category instead.
template< class T1 = mpl::arg<1>, class T2 = mpl::arg<2> >
struct minimum_category
struct minimum_category :
public min_category<T1, T2>
{
static_assert(
std::is_convertible<T1, T2>::value || std::is_convertible<T2, T1>::value,
"Iterator category types must be related through convertibility.");
using type = typename boost::iterators::detail::minimum_category_impl<
T1,
T2,
std::is_convertible<T1, T2>::value,
std::is_convertible<T2, T1>::value
>::type;
};
template <>
struct minimum_category< mpl::arg<1>, mpl::arg<2> >
{
template <class T1, class T2>
struct apply : minimum_category<T1, T2>
struct apply :
public min_category<T1, T2>
{};
};

View File

@ -61,6 +61,9 @@ test-suite iterator
[ run generator_iterator_test.cpp ]
[ run min_category.cpp ]
[ compile-fail min_category_compile_fail1.cpp ]
[ compile-fail min_category_compile_fail2.cpp ]
[ run minimum_category.cpp ]
[ compile-fail minimum_category_compile_fail.cpp ]

33
test/min_category.cpp Normal file
View File

@ -0,0 +1,33 @@
// Copyright Andrey Semashev 2025.
//
// 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)
#include <boost/iterator/min_category.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <iterator>
#include <type_traits>
using std::is_same;
using boost::iterators::min_category;
using boost::iterators::min_category_t;
int main(int, char*[])
{
BOOST_TEST_TRAIT_TRUE((is_same<min_category<std::forward_iterator_tag>::type, std::forward_iterator_tag>));
BOOST_TEST_TRAIT_TRUE((is_same<min_category<std::forward_iterator_tag, std::random_access_iterator_tag>::type, std::forward_iterator_tag>));
BOOST_TEST_TRAIT_TRUE((is_same<min_category<std::random_access_iterator_tag, std::forward_iterator_tag>::type, std::forward_iterator_tag>));
BOOST_TEST_TRAIT_TRUE((is_same<min_category<std::random_access_iterator_tag, std::random_access_iterator_tag>::type, std::random_access_iterator_tag>));
BOOST_TEST_TRAIT_TRUE((is_same<min_category<std::forward_iterator_tag, std::bidirectional_iterator_tag, std::random_access_iterator_tag>::type, std::forward_iterator_tag>));
BOOST_TEST_TRAIT_TRUE((is_same<min_category<std::random_access_iterator_tag, std::bidirectional_iterator_tag, std::forward_iterator_tag>::type, std::forward_iterator_tag>));
BOOST_TEST_TRAIT_TRUE((is_same<min_category_t<std::forward_iterator_tag>, std::forward_iterator_tag>));
BOOST_TEST_TRAIT_TRUE((is_same<min_category_t<std::forward_iterator_tag, std::random_access_iterator_tag>, std::forward_iterator_tag>));
BOOST_TEST_TRAIT_TRUE((is_same<min_category_t<std::random_access_iterator_tag, std::forward_iterator_tag>, std::forward_iterator_tag>));
BOOST_TEST_TRAIT_TRUE((is_same<min_category_t<std::random_access_iterator_tag, std::random_access_iterator_tag>, std::random_access_iterator_tag>));
BOOST_TEST_TRAIT_TRUE((is_same<min_category_t<std::forward_iterator_tag, std::bidirectional_iterator_tag, std::random_access_iterator_tag>, std::forward_iterator_tag>));
BOOST_TEST_TRAIT_TRUE((is_same<min_category_t<std::random_access_iterator_tag, std::bidirectional_iterator_tag, std::forward_iterator_tag>, std::forward_iterator_tag>));
return boost::report_errors();
}

View File

@ -0,0 +1,19 @@
// Copyright Andrey Semashev 2025.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/iterator/min_category.hpp>
using boost::iterators::min_category;
struct A {};
struct B {};
int main(int, char*[])
{
min_category<A, B>::type cat;
return 0;
}

View File

@ -0,0 +1,16 @@
// Copyright Andrey Semashev 2025.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/iterator/min_category.hpp>
using boost::iterators::min_category;
int main(int, char*[])
{
min_category<>::type cat;
return 0;
}

View File

@ -26,6 +26,7 @@
#include <boost/iterator/iterator_concepts.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/iterator/iterator_traits.hpp>
#include <boost/iterator/min_category.hpp>
#include <boost/iterator/minimum_category.hpp>
#include <boost/iterator/new_iterator_tests.hpp>
#include <boost/iterator/permutation_iterator.hpp>