#c #stl #iterator #containers #c 98
#c #stl #итератор #контейнеры #c 98
Вопрос:
Для школьного проекта я должен реализовать std::vector, но только с использованием стандарта C 98. Проблема в том, что конструктор размера и конструктор итератора конфликтуют друг с другом, когда я вызываю его с целым числом со знаком, поэтому я придумал это (с моими собственными реализациями enable_if
, is_same
, и iterator_traits
):
// Size constructor
explicit vector(
size_type count,
const T amp;value = T(),
const Allocator amp;alloc = Allocator()
) : _allocator(alloc),
_capacity(count),
_size(count),
_array(_allocator.allocate(_capacity)) {
std::fill(begin(), end(), value);
}
// Iterator constructor
template <
class InputIt
> vector(
InputIt first, InputIt last,
const Allocator amp;alloc = Allocator(),
typename ft::enable_if< ft::is_same< typename ft::iterator_traits< InputIt >::value_type, T >::value, int >::type = 0
) : _allocator(alloc),
_capacity(std::distance(first, last)),
_size(_capacity),
_array(_allocator.allocate(_capacity)) {
std::copy(first, last, begin());
}
Но теперь у меня есть проблема с моей реализацией iterator_traits
: когда я вызываю его с int
помощью, конечно, он не работает, потому int
что не имеет типов членов итератора, но когда я смотрю на cppreference about iterator_traits
, он говорит, что If Iter does not have all five member types difference_type, value_type, pointer, reference, and iterator_category, then this template has no members by any of those names (std::iterator_traits is SFINAE-friendly) (since C 17) (until C 20)
это означает, что проверка не была реализована до C 17, так как же реальная std::векторная проверка достоверности итератора еще до C 11?
Вот ошибка компилятора, которую я получаю при вызове конструктора с 2 int
s:
/home/crochu/Documents/42/ft_containers/iterator_traits.hpp:22:20: error: type 'int' cannot be used prior to '::' because it has no members
typedef typename Iter::difference_type difference_type;
^
/home/crochu/Documents/42/ft_containers/vector.hpp:78:55: note: in instantiation of template class 'ft::iterator_traits<int>' requested here
typename ft::enable_if< ft::is_same< typename ft::iterator_traits< InputIt >::value_type, T >::value, int >::type = 0
^
/home/crochu/Documents/42/ft_containers/main.cpp:19:20: note: while substituting deduced template arguments into function template 'vector' [with InputIt = int]
ft::vector< int > v(5, 42);
^
In file included from /home/crochu/Documents/42/ft_containers/main.cpp:13:
In file included from /home/crochu/Documents/42/ft_containers/ft_containers.hpp:15:
/home/crochu/Documents/42/ft_containers/iterator_traits.hpp:23:20: error: type 'int' cannot be used prior to '::' because it has no members
typedef typename Iter::value_type value_type;
^
/home/crochu/Documents/42/ft_containers/iterator_traits.hpp:24:20: error: type 'int' cannot be used prior to '::' because it has no members
typedef typename Iter::pointer pointer;
^
/home/crochu/Documents/42/ft_containers/iterator_traits.hpp:25:20: error: type 'int' cannot be used prior to '::' because it has no members
typedef typename Iter::reference reference;
^
/home/crochu/Documents/42/ft_containers/iterator_traits.hpp:26:20: error: type 'int' cannot be used prior to '::' because it has no members
typedef typename Iter::iterator_category iterator_category;
^
5 errors generated.
Комментарии:
1. Вы должны реализовать специализации ft::iterator_traits для базовых типов.
2. @S.M. Я думал об этом, но мне было интересно, есть ли более элегантный способ сделать это, и это тоже сработало бы для классов (даже если для случая vector это не будет полезно)
Ответ №1:
В качестве примера, реализация этого конструктора в libstdc находится в битах заголовка/stl_vector.h:
template<typename _InputIterator>
vector(_InputIterator __first, _InputIterator __last,
const allocator_typeamp; __a = allocator_type())
: _Base(__a)
{
// Check whether it's an integral type. If so, it's not an iterator.
typedef typename std::__is_integer<_InputIterator>::__type _Integral;
_M_initialize_dispatch(__first, __last, _Integral());
}
Это отправка тегов с использованием протокласса std::integral_constant
для одной из этих функций:
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 438. Ambiguity in the "do the right thing" clause
template<typename _Integer>
void
_M_initialize_dispatch(_Integer __n, _Integer __value, __true_type)
{
this->_M_impl._M_start = _M_allocate(_S_check_init_len(
static_cast<size_type>(__n), _M_get_Tp_allocator()));
this->_M_impl._M_end_of_storage =
this->_M_impl._M_start static_cast<size_type>(__n);
_M_fill_initialize(static_cast<size_type>(__n), __value);
}
// Called by the range constructor to implement [23.1.1]/9
template<typename _InputIterator>
void
_M_initialize_dispatch(_InputIterator __first, _InputIterator __last,
__false_type)
{
_M_range_initialize(__first, __last,
std::__iterator_category(__first));
}
Я бы сказал, что это примерно так же элегантно, как вы могли бы получить при ваших ограничениях!
Комментарии:
1. Спасибо, это именно то, что я искал