如何打印通用 std::list 迭代器?
How to print generic std::list iterator?
我希望能够通过打印其值来打印任何 std::list
迭代器。我的初始代码如下所示:
template<typename T>
std::ostream& operator<<(std::ostream& os, const typename std::list<T>::const_iterator& x)
{
return os << "&" << *x;
}
这没有用,因为编译器无法确定参数 T
。然后我尝试使它对迭代器类型本身具有通用性,并使用 iterator_traits
将其限制为迭代器。
template<
typename It,
typename = typename std::iterator_traits<It>::value_type
>
std::ostream &operator<<(std::ostream &os, const It &x)
{
return os << "&" << *x;
}
但是,当然,我得到了 std::ostream << *const char
的两个相互冲突的实现,因为指针也是迭代器。
我怎样才能将实现限制为 std::list
个迭代器,这样我就不会发生冲突?
您可以从 operator<<
重载中 SFINAE const char*
。
#include <type_traits> // std::enable_if_t, std::is_same_v, std::remove_reference_t
template<
typename It,
typename = typename std::iterator_traits<It>::value_type
>
auto operator<<(std::ostream &os, const It &x)
-> std::enable_if_t< !std::is_same_v<std::remove_reference_t<It>, const char*>, std::ostream&>
{
return os << "&" << *x;
}
注意,上面是不仅限于std::list::iterator
,意思是来自其他容器的迭代器,也可以考虑这个重载。这可能不是您想要的行为。
因为我们could not get the container type from the iterator, I would suggest the same as @super在评论中提到了。
为 Legacy Bidirectional Iterator 提供 operator<<
重载
这就是 std::list
所具有的。
以下是一个示例代码,它适用于您预期的情况以及所有满足
双向迭代器的要求。
#include <list>
#include <iostream>
#include <iterator> // std::iterator_traits, std::bidirectional_iterator_tag
#include <type_traits> // std::is_same_v, std::enable_if_t
// SFINAE helper type for bidirectional_iterator_t
template<typename Iterator, typename ReType = void>
using enable_for_bidirectional_iterator_t
= std::enable_if_t<
std::is_same_v<std::bidirectional_iterator_tag, typename std::iterator_traits<Iterator>::iterator_category>
, ReType
>;
template<typename Iterator>
auto operator<<(std::ostream& os, const Iterator x) noexcept
-> enable_for_bidirectional_iterator_t<Iterator, std::ostream&>
{
return os << "&" << *x;
}
但是,通常您会为容器而不是迭代器提供 operator<<
重载。您可能需要重新考虑设计。
您可以将类型限制为 iterator
或 const_iterator
或 std::list
。例如
template<typename It>
std::enable_if_t<std::is_same_v<It, typename std::list<typename std::iterator_traits<It>::value_type>::iterator> ||
std::is_same_v<It, typename std::list<typename std::iterator_traits<It>::value_type>::const_iterator>
, std::ostream &>
operator<<(std::ostream &os, const It &x) {
return os << "&" << *x;
}
我希望能够通过打印其值来打印任何 std::list
迭代器。我的初始代码如下所示:
template<typename T>
std::ostream& operator<<(std::ostream& os, const typename std::list<T>::const_iterator& x)
{
return os << "&" << *x;
}
这没有用,因为编译器无法确定参数 T
。然后我尝试使它对迭代器类型本身具有通用性,并使用 iterator_traits
将其限制为迭代器。
template<
typename It,
typename = typename std::iterator_traits<It>::value_type
>
std::ostream &operator<<(std::ostream &os, const It &x)
{
return os << "&" << *x;
}
但是,当然,我得到了 std::ostream << *const char
的两个相互冲突的实现,因为指针也是迭代器。
我怎样才能将实现限制为 std::list
个迭代器,这样我就不会发生冲突?
您可以从 operator<<
重载中 SFINAE const char*
。
#include <type_traits> // std::enable_if_t, std::is_same_v, std::remove_reference_t
template<
typename It,
typename = typename std::iterator_traits<It>::value_type
>
auto operator<<(std::ostream &os, const It &x)
-> std::enable_if_t< !std::is_same_v<std::remove_reference_t<It>, const char*>, std::ostream&>
{
return os << "&" << *x;
}
注意,上面是不仅限于std::list::iterator
,意思是来自其他容器的迭代器,也可以考虑这个重载。这可能不是您想要的行为。
因为我们could not get the container type from the iterator, I would suggest the same as @super在评论中提到了。
为 Legacy Bidirectional Iterator 提供 operator<<
重载
这就是 std::list
所具有的。
以下是一个示例代码,它适用于您预期的情况以及所有满足 双向迭代器的要求。
#include <list>
#include <iostream>
#include <iterator> // std::iterator_traits, std::bidirectional_iterator_tag
#include <type_traits> // std::is_same_v, std::enable_if_t
// SFINAE helper type for bidirectional_iterator_t
template<typename Iterator, typename ReType = void>
using enable_for_bidirectional_iterator_t
= std::enable_if_t<
std::is_same_v<std::bidirectional_iterator_tag, typename std::iterator_traits<Iterator>::iterator_category>
, ReType
>;
template<typename Iterator>
auto operator<<(std::ostream& os, const Iterator x) noexcept
-> enable_for_bidirectional_iterator_t<Iterator, std::ostream&>
{
return os << "&" << *x;
}
但是,通常您会为容器而不是迭代器提供 operator<<
重载。您可能需要重新考虑设计。
您可以将类型限制为 iterator
或 const_iterator
或 std::list
。例如
template<typename It>
std::enable_if_t<std::is_same_v<It, typename std::list<typename std::iterator_traits<It>::value_type>::iterator> ||
std::is_same_v<It, typename std::list<typename std::iterator_traits<It>::value_type>::const_iterator>
, std::ostream &>
operator<<(std::ostream &os, const It &x) {
return os << "&" << *x;
}