#c #iterator #containers #std
#c #итератор #контейнеры #std
Вопрос:
Я пытаюсь реализовать конструктор копирования моего пользовательского итератора, совместимого с std, для пользовательского контейнера. Контейнер выглядит примерно так:
template <typename T, Alloc>
class container {
template <typename ValueType>
class raw_iterator;
...
using value_type = T;
...
using iterator = raw_iterator<value_type>
using const_iterator = raw_iterator<const value_type>
...
}
raw_iterator выглядит примерно так:
template <typename T, Alloc>
template <typename ValueType>
class container<T, Alloc>::raw_iterator {
...
}
Если я прав, я должен реализовать конструктор копирования для обоих, итератора и const_iterator, так что итераторы могут быть скопированы в один и тот же тип, а обычный итератор может быть скопирован в const_iterator .
Как этого можно достичь?
PS: Я должен предоставить некоторую функциональность в конструкторе копирования, поэтому я не могу использовать сгенерированный implizit конструктор.
Комментарии:
1. Вы можете создать неявный конструктор для
const_iterator
, который принимаетiterator
аргумент as . Тогда все будет «просто работать».2. как я уже сказал, мне нужно добавить некоторую логику в конструктор копирования, а не только автоматически сгенерированный. Кроме того, как бы я добавил такой конструктор только для одной из настроек шаблона?
3. Хорошо, позвольте мне попробовать привести пример.
Ответ №1:
Вы можете создать неявный конструктор для const_iterator, который принимает итератор в качестве аргумента. Тогда все будет «просто работать».
Вот пример того, что, я думаю, вы хотите:
#include <type_traits>
template <typename ValueType>
class raw_iterator {
public:
// Typedefs
using non_const_value_type = std::remove_const_t<ValueType>;
using const_value_type = std::add_const_t<non_const_value_type>;
// Constructor - Need extra template argument here to allow SFINAE to work.
template <class U = ValueType,
std::enable_if_t<std::is_same<U, const_value_type>::value, int> = 0>
raw_iterator (raw_iterator<non_const_value_type> const amp; other) {
// Do stuff.
}
private:
// Friends - Make raw_iterator<X> friend of raw_iterator<X const>
friend std::conditional_t<
std::is_same<ValueType, non_const_value_type>::value,
raw_iterator<const_value_type>, void
>;
};
Существует условный конструктор, принимающий raw_iterator<AnythingNonConst>
значение, которое существует только в том случае, если raw_iterator
собственный тип temple равен AnythingConst
.
Кроме того, raw_iterator<AnythingNonConst>
является другом raw_iterator<AnythingConst>
, но не наоборот. Таким образом, вы можете копировать любые элементы, которые вы хотите, в условный конструктор.
Вот онлайн-пример: https://wandbox.org/permlink/8gDzHyheIrpsTL5y .
Комментарии:
1. perfekt, значит, std::enable_if используется для включения / отключения правильного конструктора на основе ValueType ?
2. Да, для этого используется SFINAE. Я не могу адекватно объяснить это в комментарии, но вот отправная точка, если вы хотите узнать больше: en.wikipedia.org/wiki/Substitution_failure_is_not_an_error . Об этом также есть множество статей в блоге. Это хороший трюк, который очень часто пригодится!
3. По сути, when
U != const_value_type
, thenstd::enable_if_t
— это typedef для типа, который на самом деле не существует вstd::enable_if
классе. И из-за SFINAE это не ошибка, вместо этого функция просто игнорируется компилятором. В этом случае только тогда, когдаU == const_value_type
typedef существует, и в этом случае компилятор учитывает этот конструктор.4. Это действительно в c std или это реализация компилятора? Я думаю, если это шаблон, он действителен в std…
5. Работает для всех компиляторов C , это очень «стандартный» способ выполнения действий. Мой пример кода предназначен для C 14, но вы можете легко заставить его работать и для C 11, просто нужно добавить несколько
typename
s здесь и там.