Я бы специализировал шаблон:
template <typename T>
class MyIt : public boost::iterator_adaptor<MyIt<T>, // Derived
typename T::iterator, // Base
typename T::reference> {
friend class boost::iterator_core_access;
public:
static constexpr bool is_const = false;
explicit MyIt(typename MyIt::base_type it) : MyIt::iterator_adaptor_(it) {}
};
template <typename T>
class MyIt<T const> : public boost::iterator_adaptor<MyIt<T const>, // Derived
typename T::const_iterator, // Base
typename T::const_reference> {
friend class boost::iterator_core_access;
public:
static constexpr bool is_const = true;
explicit MyIt(typename MyIt::base_type it) : MyIt::iterator_adaptor_(it) {}
};
Преобразования здесь уже разрешены, но если вы хотите иметь явное "to-const-cast", то легко написать:
template <typename T>
static MyIt<T const> make_const(MyIt<T> it) { return MyIt<T const>(it.base()); }
Используйте это:
// A template function
template <typename It> void foo(It it_begin, It it_end) {
static_assert(It::is_const == std::is_const<typename std::remove_reference<decltype(*it_begin)>::type>::value, "mismatch");
if (It::is_const)
std::cout << "Const: ";
for (auto it = it_begin; it != it_end; ++it)
std::cout << *it << " ";
std::cout << "\n";
}
Как видите, наша функция не заботится о конкретном итераторе (в этом весь смысл итераторов). Вы можете использовать его с const и non-const:
template <typename C> void foo(C const &c) {
MyIt<C const> b(c.begin()), e(c.end());
foo(b, e);
}
template <typename C> void foo(C &c) {
MyIt<C> b(c.begin()), e(c.end());
foo(b, e);
}
Быстрое демо Live On Coliru
std::vector<int> v{ 0, 1, 2, 3 };
foo(v);
auto const &constv = v;
foo(constv);
печать
void foo(C&) [with C = std::vector<int>]
0 1 2 3
void foo(const C&) [with C = std::vector<int>]
Const: 0 1 2 3
Форсирование константных итераторов
Похоже, это ваш код. Итак, давайте заставим это! Это простое изменение MyIt<C>
на MyIt<C const>
:
template <typename C> void foo(C &c) {
MyIt<C const> b(c.begin()), e(c.end()); // <--- note the const
foo(b, e);
}
Теперь foo будет вызываться с использованием константных итераторов даже для неконстантных C. Если вы считаете, что это не так, вы можете использовать помощник, показанный выше:
template <typename C> void foo(C &c) {
MyIt<C> b(c.begin()), e(c.end());
foo(make_const(b), make_const(e)); // <--- now more explicit?
}
Конечно, в foo
вы можете модифицировать static_assert
, чтобы он просто отказывался компилировать для неконстантных итераторов, во-первых:
// A template function
template <typename It> void foo(It it_begin, It it_end) {
static_assert(std::is_const<typename std::remove_reference<decltype(*it_begin)>::type>::value, "non-const disallowed");
if (It::is_const)
std::cout << "Const: ";
for (auto it = it_begin; it != it_end; ++it)
std::cout << *it << " ";
std::cout << "\n";
}
Вы можете добавить перегрузку для любого MyIt<>
, который выполняет консолидацию:
template <typename C>
typename std::enable_if<!std::is_const<C>::value>::type
foo(MyIt<C> b, MyIt<C> e) {
foo(make_const(b), make_const(e));
}
Итак, теперь каждый вызов foo
переводится в режим const
.
Полный список
Последняя полная демонстрация:
Live On Coliru
#include <boost/iterator/iterator_adaptor.hpp>
#include <iostream>
#include <vector>
template <typename T>
class MyIt : public boost::iterator_adaptor<MyIt<T>, // Derived
typename T::iterator, // Base
typename T::reference> {
friend class boost::iterator_core_access;
public:
static constexpr bool is_const = false;
explicit MyIt(typename MyIt::base_type it) : MyIt::iterator_adaptor_(it) {}
};
template <typename T>
class MyIt<T const> : public boost::iterator_adaptor<MyIt<T const>, // Derived
typename T::const_iterator, // Base
typename T::const_reference> {
friend class boost::iterator_core_access;
public:
static constexpr bool is_const = true;
explicit MyIt(typename MyIt::base_type it) : MyIt::iterator_adaptor_(it) {}
};
template <typename T>
static MyIt<T const> make_const(MyIt<T> it) { return MyIt<T const>(it.base()); }
// A template function
template <typename It> void foo(It it_begin, It it_end) {
static_assert(std::is_const<typename std::remove_reference<decltype(*it_begin)>::type>::value, "non-const disallowed");
if (It::is_const)
std::cout << "Const: ";
for (auto it = it_begin; it != it_end; ++it)
std::cout << *it << " ";
std::cout << "\n";
}
template <typename C>
typename std::enable_if<!std::is_const<C>::value>::type
foo(MyIt<C> b, MyIt<C> e) {
foo(make_const(b), make_const(e));
}
template <typename C> void foo(C &c) {
std::cout << __PRETTY_FUNCTION__ << "\n";
MyIt<C> b(c.begin()), e(c.end());
foo(b, e);
}
int main() {
std::vector<int> v{ 0, 1, 2, 3 };
foo(v);
auto const &constv = v;
foo(constv);
}
Который сейчас печатает:
void foo(C&) [with C = std::vector<int>]
Const: 0 1 2 3
void foo(C&) [with C = const std::vector<int>]
Const: 0 1 2 3