Compare commits

..
Author SHA1 Message Date
Andrey Semashev 0316628863 Reformat and simplify code. 2026-06-21 18:15:19 +03:00
Jeremy W. Murphy 286c9885d6 Constrain distance function using is_iterator type trait (#96)
* Constrain distance function using is_iterator type trait

* Add enable_if include

* Fix template syntax in distance function

* Fix syntax issue in distance enable_if

* Test which overload of distance is called

Added a test for custom distance function using Foo struct.

* Fix wrong spelling of std::ptrdiff_t

* Move Foo struct to global scope

* Andrey magic

* Fix headers, add copyright

* Constrain advance to iterators

* Test contraint of advance function with int overload

Added overload for advance function to handle integers.

* Fix enable_if condition for advance function

* Fix template syntax in advance constraint

* Fix advance test

* Remove constexpr specifier

* Make advance overload require conversion in parameter

* Explain choice of type long for n parameter
2026-06-21 18:04:10 +03:00
Andrey Semashev 4dcba468e2 Add is_*_iterator_v variable templates in C++14 and later. 2026-05-13 12:16:22 +03:00
Andrey Semashev b74b553482 Use c++23 in macos-15 GitHub Actions. 2025-12-13 20:42:38 +03:00
11 changed files with 137 additions and 6 deletions
+1 -1
View File
@@ -297,7 +297,7 @@ jobs:
cxxstd: "11,14,17,20,2b"
os: macos-14
- toolset: clang
cxxstd: "11,14,17,20,2b"
cxxstd: "11,14,17,20,23"
os: macos-15
- name: CMake tests
+5 -1
View File
@@ -7,7 +7,10 @@
#ifndef BOOST_ITERATOR_ADVANCE_HPP
#define BOOST_ITERATOR_ADVANCE_HPP
#include <type_traits>
#include <boost/config.hpp>
#include <boost/iterator/is_iterator.hpp>
#include <boost/iterator/iterator_categories.hpp>
namespace boost {
@@ -56,7 +59,8 @@ inline BOOST_CXX14_CONSTEXPR void advance_impl(RandomAccessIterator& it, Distanc
namespace advance_adl_barrier {
template< typename InputIterator, typename Distance >
inline BOOST_CXX14_CONSTEXPR void advance(InputIterator& it, Distance n)
inline BOOST_CXX14_CONSTEXPR typename std::enable_if< is_iterator< InputIterator >::value >::type
advance(InputIterator& it, Distance n)
{
detail::advance_impl(it, n, typename iterator_traversal< InputIterator >::type());
}
+8 -2
View File
@@ -1,4 +1,5 @@
// Copyright (C) 2017 Michel Morin.
// Copyright (C) 2026 Jeremy W. Murphy
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -7,7 +8,10 @@
#ifndef BOOST_ITERATOR_DISTANCE_HPP
#define BOOST_ITERATOR_DISTANCE_HPP
#include <type_traits>
#include <boost/config.hpp>
#include <boost/iterator/is_iterator.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/iterator/iterator_traits.hpp>
@@ -40,8 +44,10 @@ distance_impl(RandomAccessIterator first, RandomAccessIterator last, random_acce
namespace distance_adl_barrier {
template< typename SinglePassIterator >
inline BOOST_CXX14_CONSTEXPR typename iterator_difference< SinglePassIterator >::type
distance(SinglePassIterator first, SinglePassIterator last)
inline BOOST_CXX14_CONSTEXPR typename std::enable_if<
is_iterator< SinglePassIterator >::value,
iterator_difference< SinglePassIterator >
>::type::type distance(SinglePassIterator first, SinglePassIterator last)
{
return detail::distance_impl(first, last, typename iterator_traversal< SinglePassIterator >::type());
}
+9
View File
@@ -139,10 +139,19 @@ struct is_iterator< volatile T > : public detail::is_iterator_impl< T >::type {}
template< typename T >
struct is_iterator< const volatile T > : public detail::is_iterator_impl< T >::type {};
#if !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
template< typename T >
BOOST_INLINE_VARIABLE constexpr bool is_iterator_v = iterators::is_iterator< T >::value;
#endif // !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
} // namespace iterators
using iterators::is_iterator;
#if !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
using iterators::is_iterator_v;
#endif // !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
} // namespace boost
#endif // BOOST_ITERATOR_IS_ITERATOR_HPP_INCLUDED_
@@ -4,6 +4,7 @@
#ifndef IS_LVALUE_ITERATOR_DWA2003112_HPP
#define IS_LVALUE_ITERATOR_DWA2003112_HPP
#include <boost/config.hpp>
#include <boost/iterator/detail/type_traits/conjunction.hpp>
#include <iterator>
@@ -71,11 +72,23 @@ struct is_non_const_lvalue_iterator :
{
};
#if !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
template< typename T >
BOOST_INLINE_VARIABLE constexpr bool is_lvalue_iterator_v = iterators::is_lvalue_iterator< T >::value;
template< typename T >
BOOST_INLINE_VARIABLE constexpr bool is_non_const_lvalue_iterator_v = iterators::is_non_const_lvalue_iterator< T >::value;
#endif // !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
} // namespace iterators
using iterators::is_lvalue_iterator;
using iterators::is_non_const_lvalue_iterator;
#if !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
using iterators::is_lvalue_iterator_v;
using iterators::is_non_const_lvalue_iterator_v;
#endif // !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
} // namespace boost
#endif // IS_LVALUE_ITERATOR_DWA2003112_HPP
@@ -6,6 +6,7 @@
#include <iterator>
#include <type_traits>
#include <boost/config.hpp>
namespace boost {
namespace iterators {
@@ -60,10 +61,19 @@ struct is_readable_iterator :
{
};
#if !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
template< typename T >
BOOST_INLINE_VARIABLE constexpr bool is_readable_iterator_v = iterators::is_readable_iterator< T >::value;
#endif // !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
} // namespace iterators
using iterators::is_readable_iterator;
#if !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
using iterators::is_readable_iterator_v;
#endif // !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
} // namespace boost
#endif // IS_READABLE_ITERATOR_DWA2003112_HPP
+21
View File
@@ -20,6 +20,20 @@ void test_advance(Iterator it_from, Iterator it_to, int n)
BOOST_TEST(it_from == it_to);
}
// Definitely not an iterator
struct Foo
{
int x = 0;
// Don't use type "int" for "n", otherwise it matches literal int exactly
// and doesn't demonstrate the effect of enable_if.
friend
void advance(Foo &value, long n)
{
value.x += 10 * n;
}
};
int main()
{
int array[3] = {1, 2, 3};
@@ -87,5 +101,12 @@ int main()
);
}
{
using boost::advance;
Foo bar;
advance(bar, 3);
BOOST_TEST(bar.x == 30);
}
return boost::report_errors();
}
+14
View File
@@ -4,6 +4,7 @@
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <cstddef>
#include <vector>
#include <list>
#include <boost/container/slist.hpp>
@@ -19,6 +20,13 @@ void test_distance(Iterator it_from, Iterator it_to, int n)
BOOST_TEST(boost::distance(it_from, it_to) == n);
}
// Definitely not an iterator.
struct Foo
{
constexpr friend
std::ptrdiff_t distance(Foo const &, Foo const &) { return -1; }
};
int main()
{
int array[3] = {1, 2, 3};
@@ -80,5 +88,11 @@ int main()
);
}
{
// Make boost::distance visible since we're not actually in the boost namespace here.
using boost::distance;
auto result = distance(Foo{}, Foo{});
BOOST_TEST(result == -1);
}
return boost::report_errors();
}
+21
View File
@@ -17,6 +17,7 @@
#include <vector>
#include <string>
#include <iterator>
#include <boost/config.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/core/lightweight_test.hpp>
@@ -160,5 +161,25 @@ int main()
BOOST_TEST(!boost::iterators::is_iterator< int (&)(int) >::value);
BOOST_TEST(!boost::iterators::is_iterator< int (&)[10] >::value);
#if !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
BOOST_TEST(boost::iterators::is_iterator_v< int* >);
BOOST_TEST(boost::iterators::is_iterator_v< const int* >);
BOOST_TEST(boost::iterators::is_iterator_v< complete* >);
BOOST_TEST(boost::iterators::is_iterator_v< std::reverse_iterator< int* > >);
BOOST_TEST(boost::iterators::is_iterator_v< std::reverse_iterator< complete* > >);
BOOST_TEST(boost::iterators::is_iterator_v< adapted_iterator< int* > >);
BOOST_TEST(!boost::iterators::is_iterator_v< int >);
BOOST_TEST(!boost::iterators::is_iterator_v< void* >);
BOOST_TEST(!boost::iterators::is_iterator_v< int (int) >);
BOOST_TEST(!boost::iterators::is_iterator_v< int (*)(int) >);
BOOST_TEST(!boost::iterators::is_iterator_v< int complete::* >);
BOOST_TEST(!boost::iterators::is_iterator_v< int (complete::*)(int) >);
BOOST_TEST(!boost::iterators::is_iterator_v< int*[] >);
BOOST_TEST(!boost::iterators::is_iterator_v< int*[10] >);
BOOST_TEST(!boost::iterators::is_iterator_v< int& >);
BOOST_TEST(!boost::iterators::is_iterator_v< int*& >);
#endif // !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
return boost::report_errors();
}
+22 -1
View File
@@ -2,11 +2,12 @@
// subject to 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/is_lvalue_iterator.hpp>
#include <deque>
#include <iterator>
#include <cstddef> // std::ptrdiff_t
#include <boost/config.hpp>
#include <boost/noncopyable.hpp>
#include <boost/iterator/is_lvalue_iterator.hpp>
struct v
{
@@ -168,5 +169,25 @@ int main()
static_assert(!boost::is_non_const_lvalue_iterator<constant_lvalue_iterator<float>>::value,
"boost::is_non_const_lvalue_iterator<constant_lvalue_iterator<float>>::value is expected to be false.");
#if !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
static_assert(boost::is_lvalue_iterator_v<v*>,
"boost::is_lvalue_iterator_v<v*> is expected to be true.");
static_assert(boost::is_lvalue_iterator_v<v const*>,
"boost::is_lvalue_iterator_v<v const*> is expected to be true.");
static_assert(!boost::is_lvalue_iterator_v<proxy_iterator<int>>,
"boost::is_lvalue_iterator_v<proxy_iterator<int>> is expected to be false.");
static_assert(!boost::is_lvalue_iterator_v<value_iterator>,
"boost::is_lvalue_iterator_v<value_iterator> is expected to be false.");
static_assert(boost::is_non_const_lvalue_iterator_v<v*>,
"boost::is_non_const_lvalue_iterator_v<v*> is expected to be true.");
static_assert(!boost::is_non_const_lvalue_iterator_v<v const*>,
"boost::is_non_const_lvalue_iterator_v<v const*> is expected to be false.");
static_assert(!boost::is_non_const_lvalue_iterator_v<proxy_iterator<int>>,
"boost::is_non_const_lvalue_iterator_v<proxy_iterator<int>> is expected to be false.");
static_assert(!boost::is_non_const_lvalue_iterator_v<value_iterator>,
"boost::is_non_const_lvalue_iterator_v<value_iterator> is expected to be false.");
#endif // !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
return 0;
}
+13 -1
View File
@@ -2,11 +2,12 @@
// subject to 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/is_readable_iterator.hpp>
#include <deque>
#include <iterator>
#include <cstddef> // std::ptrdiff_t
#include <boost/config.hpp>
#include <boost/noncopyable.hpp>
#include <boost/iterator/is_readable_iterator.hpp>
struct v
{
@@ -97,5 +98,16 @@ int main()
static_assert(boost::is_readable_iterator<noncopyable_iterator>::value,
"boost::is_readable_iterator<noncopyable_iterator>::value is expected to be true.");
#if !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
static_assert(boost::is_readable_iterator_v<v*>,
"boost::is_readable_iterator_v<v*> is expected to be true.");
static_assert(boost::is_readable_iterator_v<v const*>,
"boost::is_readable_iterator_v<v const*> is expected to be true.");
static_assert(boost::is_readable_iterator_v<proxy_iterator>,
"boost::is_readable_iterator_v<proxy_iterator> is expected to be true.");
static_assert(!boost::is_readable_iterator_v<proxy_iterator2>,
"boost::is_readable_iterator_v<proxy_iterator2> is expected to be false.");
#endif // !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
return 0;
}