![](/img/trans.png)
[英]Why is nullptr a part of the core language, but nullptr_t is a part of STL?
[英]Template function for STL iterators, pointers and std::nullptr_t
我正在嘗試圍繞基於 c 的 API function 編寫一個包裝器。
用戶應該能夠將 RandomAccessIterators、指針或 nullptr 作為參數傳遞給包裝器 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;
}
此代碼無法編譯,因為std::iterator_traits<T>
不是專門用於std::nullptr_t
。
我已經想出了兩種可能的解決方案:
1.) 特化std::iterator_traits<std::nullptr_t>
,例如:
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;
};
}
但據我所知,專門 stl 命名空間成員會很快導致未定義的行為。
2.) 將功能拆分為兩個功能。 這里的問題是它會導致不必要的復制粘貼代碼。 此外,我想在原始 function 中添加幾個重載,這將導致最后的函數數量增加兩倍(例如,對於 4 個正常重載,我需要使用這種方法進行 8 個重載)。
所以我的問題是:
有沒有辦法通過不引入可能的未定義行為並且必須創建兩倍數量的重載函數來解決這個問題?
例如,調整is_random_access_iterator_v
特征使其不依賴於std::iterator_traits
?
您不能專門std::iterator_traits<std::nullptr_t>
,但您可以創建自己的特征:
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;
};
並根據您的需要使用my_iterator_traits
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.