mirror of
https://github.com/ETLCPP/etl.git
synced 2026-06-15 08:26:04 +08:00
Fix iterator_traits: make SFINAE-friendly for iterators without nested typedefs (#1447)
The primary etl::iterator_traits template previously required all five nested typedefs (iterator_category, value_type, difference_type, pointer, reference) to exist, causing hard compilation errors with iterators like std::common_iterator or ranges::common_iterator. Changes: 1. Make primary template SFINAE-friendly: split into an empty primary template and a void_t-guarded partial specialization that only activates when all nested typedefs are present. 2. Add explicit std::common_iterator specialization (C++20/STL): a partial specialization that delegates to std::iterator_traits<std::common_iterator<I,S>>. 3. Fall through to std::iterator_traits: the empty primary template inherits from std::iterator_traits<TIterator> when building with STL and C++20, so any iterator with a std::iterator_traits specialization works automatically. 4. Remove iterator_traits dependency from etl::vector: assign() now uses decltype(*first) for the type-compatibility static assert, and insert() uses ptrdiff_t directly instead of querying iterator_traits<TIterator>::difference_type.
This commit is contained in:
parent
9765cbf764
commit
af3944acdb
@ -68,9 +68,22 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// iterator_traits
|
||||
|
||||
// For anything not a fundamental type.
|
||||
template <typename TIterator, typename = typename etl::enable_if< !etl::is_fundamental<TIterator>::value, void>::type>
|
||||
#if ETL_USING_CPP11
|
||||
|
||||
// Primary template: falls through to std::iterator_traits when STL is available (C++20+),
|
||||
// otherwise empty (SFINAE-safe fallback for iterators without nested typedefs).
|
||||
template <typename TIterator, typename = void>
|
||||
struct iterator_traits
|
||||
#if ETL_USING_STL && ETL_USING_CPP20
|
||||
: std::iterator_traits<TIterator>
|
||||
#endif
|
||||
{
|
||||
};
|
||||
|
||||
// Specialization for iterators that define the standard nested typedefs.
|
||||
template <typename TIterator>
|
||||
struct iterator_traits<TIterator, etl::void_t< typename TIterator::iterator_category, typename TIterator::value_type,
|
||||
typename TIterator::difference_type, typename TIterator::pointer, typename TIterator::reference >>
|
||||
{
|
||||
typedef typename TIterator::iterator_category iterator_category;
|
||||
typedef typename TIterator::value_type value_type;
|
||||
@ -79,6 +92,14 @@ namespace etl
|
||||
typedef typename TIterator::reference reference;
|
||||
};
|
||||
|
||||
#if ETL_USING_STL && ETL_USING_CPP20
|
||||
// Specialization for std::common_iterator (C++20).
|
||||
template <typename I, typename S>
|
||||
struct iterator_traits<std::common_iterator<I, S>, void> : std::iterator_traits<std::common_iterator<I, S>>
|
||||
{
|
||||
};
|
||||
#endif
|
||||
|
||||
// For pointers.
|
||||
template <typename T>
|
||||
struct iterator_traits<T*, void>
|
||||
@ -101,6 +122,43 @@ namespace etl
|
||||
typedef const T& reference;
|
||||
};
|
||||
|
||||
#else // C++03
|
||||
|
||||
// Primary template: unconditionally extracts nested typedefs.
|
||||
template <typename TIterator>
|
||||
struct iterator_traits
|
||||
{
|
||||
typedef typename TIterator::iterator_category iterator_category;
|
||||
typedef typename TIterator::value_type value_type;
|
||||
typedef typename TIterator::difference_type difference_type;
|
||||
typedef typename TIterator::pointer pointer;
|
||||
typedef typename TIterator::reference reference;
|
||||
};
|
||||
|
||||
// For pointers.
|
||||
template <typename T>
|
||||
struct iterator_traits<T*>
|
||||
{
|
||||
typedef ETL_OR_STD::random_access_iterator_tag iterator_category;
|
||||
typedef T value_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef typename etl::remove_cv<T>::type* pointer;
|
||||
typedef T& reference;
|
||||
};
|
||||
|
||||
// For const pointers.
|
||||
template <typename T>
|
||||
struct iterator_traits<const T*>
|
||||
{
|
||||
typedef ETL_OR_STD::random_access_iterator_tag iterator_category;
|
||||
typedef T value_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef const typename etl::remove_cv<T>::type* pointer;
|
||||
typedef const T& reference;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
// advance
|
||||
template <typename TIterator, typename TDistance>
|
||||
|
||||
@ -390,9 +390,11 @@ namespace etl
|
||||
template <typename TIterator>
|
||||
typename etl::enable_if<!etl::is_integral<TIterator>::value, void>::type assign(TIterator first, TIterator last)
|
||||
{
|
||||
#if ETL_USING_CPP11
|
||||
ETL_STATIC_ASSERT((etl::is_same<typename etl::remove_cv<T>::type,
|
||||
typename etl::remove_cv< typename etl::iterator_traits< TIterator>::value_type>::type>::value),
|
||||
typename etl::remove_cv<typename etl::remove_reference<decltype(*first)>::type>::type>::value),
|
||||
"Iterator type does not match container type");
|
||||
#endif
|
||||
|
||||
#if ETL_IS_DEBUG_BUILD
|
||||
difference_type d = etl::distance(first, last);
|
||||
@ -895,12 +897,11 @@ namespace etl
|
||||
etl::move_backward(p_buffer + insert_begin, p_buffer + insert_begin + copy_old_n, p_buffer + insert_end + copy_old_n);
|
||||
|
||||
// Copy construct new.
|
||||
typedef typename etl::iterator_traits<TIterator>::difference_type diff_t;
|
||||
etl::uninitialized_copy(first + static_cast<diff_t>(copy_new_n), first + static_cast<diff_t>(copy_new_n + construct_new_n), p_end);
|
||||
etl::uninitialized_copy(first + static_cast<ptrdiff_t>(copy_new_n), first + static_cast<ptrdiff_t>(copy_new_n + construct_new_n), p_end);
|
||||
ETL_ADD_DEBUG_COUNT(construct_new_n);
|
||||
|
||||
// Copy new.
|
||||
etl::copy(first, first + static_cast<diff_t>(copy_new_n), p_buffer + insert_begin);
|
||||
etl::copy(first, first + static_cast<ptrdiff_t>(copy_new_n), p_buffer + insert_begin);
|
||||
|
||||
p_end += count;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user