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; 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: public:
//********************************************************************* //*********************************************************************
@ -320,7 +327,7 @@ namespace etl
///\param last The iterator to the last element + 1. ///\param last The iterator to the last element + 1.
//********************************************************************* //*********************************************************************
template <typename TIterator> 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); base_t::assign(first, last);
} }
@ -440,8 +447,8 @@ namespace etl
///\param first The first element to add. ///\param first The first element to add.
///\param last The last + 1 element to add. ///\param last The last + 1 element to add.
//********************************************************************* //*********************************************************************
template <class TIterator> template <typename TIterator>
void insert(const_iterator position, TIterator first, TIterator last) 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); base_t::insert(base_t::iterator(position), first, last);
} }
@ -573,6 +580,13 @@ namespace etl
typedef pvoidvector base_t; 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: public:
//********************************************************************* //*********************************************************************
@ -823,7 +837,7 @@ namespace etl
///\param last The iterator to the last element + 1. ///\param last The iterator to the last element + 1.
//********************************************************************* //*********************************************************************
template <typename TIterator> 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); base_t::assign(first, last);
} }
@ -901,8 +915,8 @@ namespace etl
///\param first The first element to add. ///\param first The first element to add.
///\param last The last + 1 element to add. ///\param last The last + 1 element to add.
//********************************************************************* //*********************************************************************
template <class TIterator> template <typename TIterator>
void insert(const_iterator position, TIterator first, TIterator last) 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); 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.size() == swap_other_data.size());
CHECK(etl_data2.max_size() == other_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 } // namespace