Как определить тип итератора для постоянной и неконстантной версии контейнера

#c #templates #stl

Вопрос:

Рассмотрим этот пример:

 template <typename T> struct A {
    using Iter = typename T::iterator;
    Iter iter;
    A(Tamp; cont) {
        iter = cont.begin();
    }
    typename Iter::reference value() { return *iter; }
};

void f(std::vector<int>amp; v) {
    A a(v);
    a.value() = 10;
}
 

Это работает нормально, покупайте, если вы добавляете const в тип контейнера, это больше не компиляция!

 int g(const std::vector<int>amp; v) {
    A a(v); // ERROR
    return a.value();
}
 

Как определить тип итератора, который будет компилироваться с типом контейнера const/non-const.
Мне нужно что-то подобное:

 using Iter = decltype(T::begin());
 

Комментарии:

1. Что вы делаете с этим итератором? Собираетесь ли вы изменить то, на что это указывает? Если нет, просто используйте T::const_iterator и всегда приводите итератор к константе.

2. Итератор должен разрешить модификацию, если контейнер не является постоянным

3. @NathanOliver Я отредактировал сообщение

Ответ №1:

Идея 1: проверьте тип итератора напрямую.

Реализация:

    using Iter = decltype(std::declval<T>()::begin());
 

Идея 2: проверьте, соответствует ли тип const , и определите итератор, используя эти знания.

Реализация:

 #include <vector>
#include <type_traits>

template <typename T> struct A {
    using Iter = std::conditional_t<
                        std::is_same_v<std::remove_const_t<T>, T>, typename T::iterator, typename T::const_iterator
                                   >;
    Iter iter;
    A(Tamp; cont) {
        iter = cont.begin();
    }
};

void f(const std::vector<int>amp; v) {
    A a(v);
}


void f1(std::vector<int>amp; v) {
    A a(v);
}
 

Комментарии:

1. Идея 1 не скомпилирована gcc 10, но идея 2 работает! Спасибо тебе!

2. @user3324131 извините, произошла опечатка, Идея 1 есть decltype(std::declval<T>().begin()); . Это должно сработать.