专门C++使用指针值类型的通用迭代器的模板函数?

Specialize C++ template function that uses generic iterators for pointer value type?

本文关键字:迭代器 函数 类型 C++ 指针 专门      更新时间:2023-10-16

我有一个C++模板函数,它接受泛型迭代器作为参数,如下所示:

(它处理从first到但不包括last的所有元素(

void update(const std::uint8_t *const data, const size_t len)
{
/* ... */
}
template<typename iterator_type>
void update(const iterator_type &first, const iterator_type &last)
{
typedef typename std::iterator_traits<iterator_type>::value_type value_type;
for (iterator_type iter = first; iter != last; ++iter)
{
update(reinterpret_cast<const std::uint8_t*>(std::addressof(*iter)), sizeof(value_type));
}
}

到目前为止,这是有效的。我唯一的问题是:如果迭代器的value_type恰好是指针类型,则此函数处理指针值(内存地址(而不是指针指向的实际值(对象(。所以,我想专门处理指针类型。C++有没有一种好方法可以为value_type为指针类型的迭代器提供此模板函数的专用化?

我试图用一个函数和一个if(is_pointer)... else...结构来解决这个问题,如下所示:

void update(const iterator_type &first, const iterator_type &last)
{
typedef typename std::iterator_traits<iterator_type>::value_type value_type;
if(std::is_pointer<value_type>::value)
{
for (iterator_type iter = first; iter != last; ++iter)
{
update(reinterpret_cast<const std::uint8_t*>(*iter), sizeof(std::pointer_traits<value_type>::element_type));
}
}
else
{
for (iterator_type iter = first; iter != last; ++iter)
{
update(reinterpret_cast<const std::uint8_t*>(std::addressof(*iter)), sizeof(value_type));
}
}
}

。但是,不幸的是,这不适用于非指针类型:

error C2039: 'element_type': is not a member of 'std::pointer_traits<value_type>'

编写模板函子来更新单个项目并对其进行专用化会更容易。然后,让更新模板函数调用该类。像这样:

template <typename T>
struct Update {
void operator () (const T &v) {
//...
}
};
template <typename T>
struct Update<T *> {
void operator () (const T *v) {
//...
}
};

template <typename T>
void update (const T &v) {
Update<T>()(v);
}

然后在循环中,你这样称呼它:

update(*iter);

您可以将更新函子参数化到更新函数模板中,以便在调用方想要执行与默认更新处理不同的操作时为其提供灵活性。

template <typename T, typename U = Update<T>>
void update (const T &v, U u = U{}) {
u(v);
}

然后,前面的调用仍然有效,但您也可以传入不同的可调用对象(如 lambda(。

update(*iter, [](int *){ /* ... */ });

这个问题已经有一个很好的答案,但我在这里提出类型特征和标签调度使得具有指针和非指针值类型的迭代器之间的重载变得容易:

template <typename T>
void update_tag_dispatch(T first, T last, std::true_type) {
std::cout << "iterator value is a pointer!n";
}
template <typename T>
void update_tag_dispatch(T first, T last, std::false_type) {
std::cout << "iterator value is not a pointern";
}
template <typename T>
void update_tag_dispatch(T first, T last) {
update_tag_dispatch(first, last, std::is_pointer<std::remove_reference_t<decltype(*first)>>{});
}

你也可以使用它的表亲,std::enable_if_t

template <typename T, std::enable_if_t<std::is_pointer<std::remove_reference_t<decltype(*std::declval<T>())>>::value>* = nullptr>
void update_enable_t(T first, T last) {
std::cout << "iterator value is a pointer!n";
}
template <typename T, std::enable_if_t<!std::is_pointer<std::remove_reference_t<decltype(*std::declval<T>())>>::value>* = nullptr>
void update_enable_t(T first, T last) {
std::cout << "iterator value is a pointer!n";
}

演示:https://godbolt.org/z/t7YbcF