简体   繁体   中英

Template function for STL iterators, pointers and std::nullptr_t

I'm trying to write a wrapper around a c-based API function.
The user should be able to pass RandomAccessIterators, pointers or the nullptr as parameters to the wrapper function.

#include <type_traits>
#include <iterator>

template <typename Iter>
constexpr bool is_random_access_iterator_v = std::is_convertible_v<typename std::iterator_traits<Iter>::iterator_category, std::random_access_iterator_tag>;

template <typename Iter>
using iterater_decayed_type_t = std::decay_t<typename std::iterator_traits<Iter>::value_type>;

// convert iterator to pointer
template <typename Iter>
auto get_pointer(Iter it) {
    if constexpr (std::is_null_pointer_v<Iter> || std::is_pointer_v<Iter>) {
        return it;
    } else {
        return &*it;
    }
}

// InputIter and OutputIter can be arbitrary iterator or pointer. 
// OutputIter can also be a nullptr
template <typename InputIter, typename OutputIter>
OutputIter wrapper(InputIter first, InputIter last, OutputIter d_first) {
    static_assert(is_random_access_iterator_v<InputIter>, "InputIter needs to be a RandomAccessIterator");
    static_assert(std::is_null_pointer_v<OutputIter> || is_random_access_iterator_v<OutputIter>, "OutputIter needs to be a RandomAccessIterator or nullptr");
    static_assert(std::is_null_pointer_v<OutputIter> || std::is_same_v<iterater_decayed_type_t<InputIter>, iterater_decayed_type_t<OutputIter>>, "Iterator value types must be identical or OutputIter is nullptr");

    using value_t = iterater_decayed_type_t<InputIter>;

    using first_ptr_t = typename std::iterator_traits<InputIter>::pointer;
    first_ptr_t ptr_first = get_pointer(first);

    using d_first_ptr_t = std::conditional_t<std::is_null_pointer_v<OutputIter>, std::nullptr_t, typename std::iterator_traits<OutputIter>::pointer>;
    d_first_ptr_t ptr_d_first = get_pointer(d_first);

    // func gets arbitrary pointers (void*)
    func(ptr_first, ptr_d_first, last - first);
    return d_first;
}

This code doesn't compile because std::iterator_traits<T> isn't specialized for std::nullptr_t .

I already came up with two possible solutions:

1.) Specialize std::iterator_traits<std::nullptr_t> , eg:

namespace std {
    template <>
    struct iterator_traits<std::nullptr_t> {
        using difference_type = std::ptrdiff_t;
        using value_type = std::nullptr_t;
        using pointer = std::nullptr_t;
        using reference = std::nullptr_t;
        using iterator_category = std::random_access_iterator_tag;
        using iterator_concept = std::random_access_iterator_tag;
    };
}

But as far as I know specializing stl namespace members can quickly lead to undefined behavior.

2.) Split the functionality in two functions. The problem here is that it would lead to unnecessary copy-paste code. Additionally I want to add several overloads to the original function which would lead to two times the number of functions at the end (eg for 4 normal overloads I would require 8 overloads with this approach).

So my question is:
Is there any way to solve this problem by not introducing possible undefined behavior and having to create two times the number of overloaded functions?
For example tweaking the is_random_access_iterator_v trait to not rely on std::iterator_traits ?

You cannot specialize std::iterator_traits<std::nullptr_t> , but you can create your own traits:

template <typename T>
struct my_iterator_traits : iterator_traits<T> {};

template <>
struct my_iterator_traits<std::nullptr_t>
{
    using difference_type = std::ptrdiff_t;
    using value_type = std::nullptr_t;
    using pointer = std::nullptr_t;
    using reference = std::nullptr_t;
    using iterator_category = std::random_access_iterator_tag;
    using iterator_concept = std::random_access_iterator_tag;
};

and use my_iterator_traits for your needs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM