Only enable the assign and insert member functions for class ivector<… (#1467)

* Only enable the assign and insert member functions for class ivector<T*> & class ivector<const T*> when the value_type the iterator references is a pointer to T.

* Imporoved enable_if for assign and insert.

* clang-format

* std::void_t -> etl::void_t

* Made enable_if condition into a common class struct

---------

Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com>
This commit is contained in:
John Wellbelove 2026-06-20 10:26:03 +01:00 committed by GitHub
parent 04b7004110
commit 55429eddd2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 63 additions and 6 deletions

View File

@ -70,6 +70,13 @@ namespace etl
typedef pvoidvector base_t;
template <typename TIterator>
struct is_compatible_iterator
: etl::integral_constant<bool, etl::is_pointer<typename etl::iterator_traits<TIterator>::value_type>::value
&& etl::is_convertible<typename etl::iterator_traits<TIterator>::value_type, value_type>::value>
{
};
public:
//*********************************************************************
@ -320,7 +327,7 @@ namespace etl
///\param last The iterator to the last element + 1.
//*********************************************************************
template <typename TIterator>
void assign(TIterator first, TIterator last)
typename etl::enable_if< is_compatible_iterator<TIterator>::value, void>::type assign(TIterator first, TIterator last)
{
base_t::assign(first, last);
}
@ -440,8 +447,8 @@ namespace etl
///\param first The first element to add.
///\param last The last + 1 element to add.
//*********************************************************************
template <class TIterator>
void insert(const_iterator position, TIterator first, TIterator last)
template <typename TIterator>
typename etl::enable_if< is_compatible_iterator<TIterator>::value, void>::type insert(const_iterator position, TIterator first, TIterator last)
{
base_t::insert(base_t::iterator(position), first, last);
}
@ -573,6 +580,13 @@ namespace etl
typedef pvoidvector base_t;
template <typename TIterator>
struct is_compatible_iterator
: etl::integral_constant<bool, etl::is_pointer<typename etl::iterator_traits<TIterator>::value_type>::value
&& etl::is_convertible<typename etl::iterator_traits<TIterator>::value_type, value_type>::value>
{
};
public:
//*********************************************************************
@ -823,7 +837,7 @@ namespace etl
///\param last The iterator to the last element + 1.
//*********************************************************************
template <typename TIterator>
void assign(TIterator first, TIterator last)
typename etl::enable_if< is_compatible_iterator<TIterator>::value, void>::type assign(TIterator first, TIterator last)
{
base_t::assign(first, last);
}
@ -901,8 +915,8 @@ namespace etl
///\param first The first element to add.
///\param last The last + 1 element to add.
//*********************************************************************
template <class TIterator>
void insert(const_iterator position, TIterator first, TIterator last)
template <typename TIterator>
typename etl::enable_if< is_compatible_iterator<TIterator>::value, void>::type insert(const_iterator position, TIterator first, TIterator last)
{
base_t::insert(base_t::iterator(position), first, last);
}

View File

@ -1683,5 +1683,48 @@ namespace
CHECK(etl_data2.size() == swap_other_data.size());
CHECK(etl_data2.max_size() == other_size);
}
//*************************************************************************
template <typename TContainer, typename TIterator, typename = void>
struct is_assign_callable : std::false_type
{
};
template <typename TContainer, typename TIterator>
struct is_assign_callable<TContainer, TIterator,
etl::void_t<decltype(std::declval<TContainer&>().assign(std::declval<TIterator>(), std::declval<TIterator>()))>>
: std::true_type
{
};
template <typename TContainer, typename TIterator1, typename TIterator2, typename = void>
struct is_insert_callable : std::false_type
{
};
template <typename TContainer, typename TIterator1, typename TIterator2>
struct is_insert_callable<
TContainer, TIterator1, TIterator2,
etl::void_t<decltype(std::declval<TContainer&>().insert(std::declval<TIterator1>(), std::declval<TIterator2>(), std::declval<TIterator2>()))>>
: std::true_type
{
};
TEST_FIXTURE(SetupFixture, test_issue_1464_etl_vector_insert_allows_inserting_an_incompatible_type)
{
struct SomeStruct
{
int foo;
};
using ContainerType = etl::vector<SomeStruct*, 4>;
using Iterator1Type = etl::vector<SomeStruct*, 4>::iterator;
using Iterator2Type = etl::vector<SomeStruct, 4>::const_iterator;
constexpr bool can_assign = is_assign_callable<ContainerType, Iterator2Type>::value;
CHECK_FALSE(can_assign);
constexpr bool can_insert = is_insert_callable<ContainerType, Iterator1Type, Iterator2Type>::value;
CHECK_FALSE(can_insert);
}
}
} // namespace