#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());
. Это должно сработать.