C++ 一种将迭代器转换为常量迭代器的方法
我正在编写一个由迭代器参数化的容器视图,我需要知道常量迭代器的类型是什么。大概是这样的:C++ 一种将迭代器转换为常量迭代器的方法,c++,iterator,C++,Iterator,我正在编写一个由迭代器参数化的容器视图,我需要知道常量迭代器的类型是什么。大概是这样的: template <typename It> // It = random access iterator class Container_view{ using value_type = typename std::iterator_traits<It>::value_type; using reference = ... ... using i
template <typename It>
// It = random access iterator
class Container_view{
using value_type = typename std::iterator_traits<It>::value_type;
using reference = ...
...
using iterator = It;
using const_iterator = ???
};
为什么容器视图要由迭代器而不是容器本身来参数化呢?如果您了解容器的类型,就很容易了。我认为
template class Container\u view
是一种方法。我更喜欢使用迭代器,因为我使用的是矩阵。如果我使用迭代器,子矩阵、矩阵视图和子矩阵视图的实现都是同一个类。如果您使用容器作为参数,如何使用相同的代码实现子矩阵和矩阵视图?简单的回答是-您所要求的是不可能的。迭代器
只提供有关自身的信息。它不提供关于其他迭代器类型或它来自的容器的任何信息。只有容器知道它的迭代器和常量迭代器使用的类型。因此,您需要访问视图类中的容器。
// about dependent_false: https://en.cppreference.com/w/cpp/language/if
template <typename T>
struct dependent_false : std::false_type { };
// has_const_iterator is true if has const_iterator member, otherwise
// is false. More info: https://en.cppreference.com/w/cpp/types/void_t
template <typename, typename = std::void_t<>>
struct has_const_iterator: std::false_type { };
template <typename T>
struct has_const_iterator<T, std::void_t<typename T::const_iterator>>
: std::true_type { };
template <typename T>
inline constexpr bool has_const_iterator_v = has_const_iterator<T>::value;
// has_value_type true if the class has value_type, otherwise is false
template <typename, typename = std::void_t<>>
struct has_value_type : std::false_type { };
template <typename T>
struct has_value_type<T, std::void_t<typename T::value_type>>
: std::true_type { };
template <typename T>
inline constexpr bool has_value_type_v = has_value_type<T>::value;
namespace alp{
template <typename It>
constexpr decltype(auto) select_const_iterator()
{
if constexpr (has_const_iterator_v<It>)
return typename It::const_iterator{};
else if constexpr (std::is_pointer_v<It>){
using value_type = std::remove_pointer_t<It>;
using const_pointer = const value_type*;
return const_pointer{0};
}
else if constexpr (has_value_type_v<It>){
using value_type = typename It::value_type;
if constexpr (std::is_same_v<typename std::vector<value_type>::iterator,
It>)
return typename std::vector<value_type>::const_iterator();
}
else
static_assert(dependent_false<It>::value, "TODO");
}
template <typename It>
struct iterator_traits{
using const_iterator = decltype(select_const_iterator<It>());
};
}// namespace
struct A
{
using const_iterator = int;
};
struct B{};
int main()
{
std::cout << std::boolalpha
<< std::is_same_v<typename alp::iterator_traits<A>::const_iterator, int>
<< '\n'
<< std::is_same_v<typename alp::iterator_traits<int*>::const_iterator,
const int*>
// not compile:
// << std::is_same_v<typename alp::iterator_traits<B>::const_iterator, const B>
<< '\n';
using it = std::vector<int>::iterator;
std::cout << std::is_same_v<alp::iterator_traits<it>::const_iterator,
std::vector<int>::const_iterator>
<< '\n';
}