从 back_insert_iterator 中提取容器 value_type 的特征 class
Traits class to extract container's value_type from a back_insert_iterator
std::back_insert_iterator
有 value_type
等于 void
,但它也有一个 protected
成员 container
持有指向基础 Container
。我正在尝试编写一个特征 class 来提取容器的 value_type
,沿着这些行:
#include <iterator>
#include <type_traits>
#include <vector>
template<class OutputIt>
struct outit_vt
:
OutputIt
{
using self_type = outit_vt<OutputIt>;
using value_type = typename std::remove_pointer_t<decltype(std::declval<self_type>().container)>::value_type;
};
int main()
{
std::vector<int> v;
auto it = std::back_inserter(v);
static_assert(std::is_same<outit_vt<decltype(it)>::value_type, int>::value, "");
}
然而,这(或多或少是意料之中的)遇到了不完整的类型错误。无论如何,为了提取容器的 value_type
?
您可以只使用 container_type
它具有:
#include <iterator>
#include <type_traits>
#include <vector>
template<typename T>
struct outit_v {
using container_type = typename T::container_type;
using value_type = typename container_type::value_type;
};
int main()
{
std::vector<int> v;
auto it = std::back_inserter(v);
static_assert(std::is_same<outit_v<decltype(it)>::value_type, int>::value, "");
}
@Rapptz 的回答是正确的,但对于通用代码(即当先验不清楚是否处理原始 T*
或 back_insert_iterator
或标准库的其他代码之一时输出迭代器),更系统的方法是必要的。
为此,在 user-defined namespace xstd
中定义 class 模板 output_iterator_traits
。
#include <iterator> // iterator, iterator_traits, input_iterator_tag, output_iterator_tag, random_access_iterator_tag
// back_insert_iterator, front_insert_iterator, insert_iterator, ostream_iterator, ostreambuf_iterator
#include <memory> // raw_storage_iterator
namespace xstd {
template<class T>
struct output_iterator_traits
:
std::iterator_traits<T>
{};
template< class OutputIt, class T>
struct output_iterator_traits<std::raw_storage_iterator<OutputIt, T>>
:
std::iterator<std::output_iterator_tag, T>
{};
template<class Container>
struct output_iterator_traits<std::back_insert_iterator<Container>>
:
std::iterator<std::output_iterator_tag, typename Container::value_type>
{};
template<class Container>
struct output_iterator_traits<std::front_insert_iterator<Container>>
:
std::iterator<std::output_iterator_tag, typename Container::value_type>
{};
template<class Container>
struct output_iterator_traits<std::insert_iterator<Container>>
:
std::iterator<std::output_iterator_tag, typename Container::value_type>
{};
template <class T, class charT, class traits>
struct output_iterator_traits<std::ostream_iterator<T, charT, traits>>
:
std::iterator<std::output_iterator_tag, T>
{};
template <class charT, class traits>
struct output_iterator_traits<std::ostreambuf_iterator<charT, traits>>
:
std::iterator<std::output_iterator_tag, charT>
{};
} // namespace xstd
非特化版本简单地继承自std::iterator_traits<T>
,但是对于<iterator>
和<memory>
headers中定义的6个输出迭代器,特化版本继承自[=19] =] 其中 V
是作为迭代器的 operator=(const V&)
参数出现的类型。
对于插入迭代器,这对应于 typename Container::value_type
,对于原始存储迭代器,对应于 T
,对于 ostream
和 ostreambuf
迭代器,对应于 T
和 charT
。
形式为
的通用算法
template<class InputIt, class OutputIt>
auto my_fancy_algorithm(InputIt first, InputIt last, OutputIt dest)
{
using T = typename xstd::output_iterator_traits<OutputIt>::value_type;
for (; first != last; ++first) {
// ... construct arguments from *first
*dest++ = T{ /* arguments */ };
}
}
然后将透明地使用原始指针和标准库的输出迭代器。
std::back_insert_iterator
有 value_type
等于 void
,但它也有一个 protected
成员 container
持有指向基础 Container
。我正在尝试编写一个特征 class 来提取容器的 value_type
,沿着这些行:
#include <iterator>
#include <type_traits>
#include <vector>
template<class OutputIt>
struct outit_vt
:
OutputIt
{
using self_type = outit_vt<OutputIt>;
using value_type = typename std::remove_pointer_t<decltype(std::declval<self_type>().container)>::value_type;
};
int main()
{
std::vector<int> v;
auto it = std::back_inserter(v);
static_assert(std::is_same<outit_vt<decltype(it)>::value_type, int>::value, "");
}
然而,这(或多或少是意料之中的)遇到了不完整的类型错误。无论如何,为了提取容器的 value_type
?
您可以只使用 container_type
它具有:
#include <iterator>
#include <type_traits>
#include <vector>
template<typename T>
struct outit_v {
using container_type = typename T::container_type;
using value_type = typename container_type::value_type;
};
int main()
{
std::vector<int> v;
auto it = std::back_inserter(v);
static_assert(std::is_same<outit_v<decltype(it)>::value_type, int>::value, "");
}
@Rapptz 的回答是正确的,但对于通用代码(即当先验不清楚是否处理原始 T*
或 back_insert_iterator
或标准库的其他代码之一时输出迭代器),更系统的方法是必要的。
为此,在 user-defined namespace xstd
中定义 class 模板 output_iterator_traits
。
#include <iterator> // iterator, iterator_traits, input_iterator_tag, output_iterator_tag, random_access_iterator_tag
// back_insert_iterator, front_insert_iterator, insert_iterator, ostream_iterator, ostreambuf_iterator
#include <memory> // raw_storage_iterator
namespace xstd {
template<class T>
struct output_iterator_traits
:
std::iterator_traits<T>
{};
template< class OutputIt, class T>
struct output_iterator_traits<std::raw_storage_iterator<OutputIt, T>>
:
std::iterator<std::output_iterator_tag, T>
{};
template<class Container>
struct output_iterator_traits<std::back_insert_iterator<Container>>
:
std::iterator<std::output_iterator_tag, typename Container::value_type>
{};
template<class Container>
struct output_iterator_traits<std::front_insert_iterator<Container>>
:
std::iterator<std::output_iterator_tag, typename Container::value_type>
{};
template<class Container>
struct output_iterator_traits<std::insert_iterator<Container>>
:
std::iterator<std::output_iterator_tag, typename Container::value_type>
{};
template <class T, class charT, class traits>
struct output_iterator_traits<std::ostream_iterator<T, charT, traits>>
:
std::iterator<std::output_iterator_tag, T>
{};
template <class charT, class traits>
struct output_iterator_traits<std::ostreambuf_iterator<charT, traits>>
:
std::iterator<std::output_iterator_tag, charT>
{};
} // namespace xstd
非特化版本简单地继承自std::iterator_traits<T>
,但是对于<iterator>
和<memory>
headers中定义的6个输出迭代器,特化版本继承自[=19] =] 其中 V
是作为迭代器的 operator=(const V&)
参数出现的类型。
对于插入迭代器,这对应于 typename Container::value_type
,对于原始存储迭代器,对应于 T
,对于 ostream
和 ostreambuf
迭代器,对应于 T
和 charT
。
形式为
的通用算法template<class InputIt, class OutputIt>
auto my_fancy_algorithm(InputIt first, InputIt last, OutputIt dest)
{
using T = typename xstd::output_iterator_traits<OutputIt>::value_type;
for (; first != last; ++first) {
// ... construct arguments from *first
*dest++ = T{ /* arguments */ };
}
}
然后将透明地使用原始指针和标准库的输出迭代器。