簡體   English   中英

std :: enable_if或SFINAE用於迭代器或指針

[英]std::enable_if or SFINAE for iterator or pointer

我想為MyClass編寫一個帶參數的構造函數,我希望只有在參數是pointeriterator (具有iterator_traits東西)時才能編譯它。 怎么做到這一點?

遺憾的是,沒有標准的方法來檢測一個類是否為Iterator模型。 最簡單的檢查是*it++it在語法上都是有效的; 你可以使用標准的SFINAE技術做到這一點:

template<typename T,
    typename = decltype(*std::declval<T&>(), void(), ++std::declval<T&>(), void())>
    MyClass(T);

考慮24.2.2:2中的Iterator要求:

template<typename T> typename std::enable_if<
    !std::is_void<decltype(*std::declval<T &>())>::value
    && std::is_same<decltype(++std::declval<T &>()),
                    typename std::add_lvalue_reference<T>::type>::value,
    std::true_type>::type has_iterator_requirements_helper(int);
template<typename T> std::false_type has_iterator_requirements_helper(...);
template<typename T> struct has_iterator_requirements:
    decltype(has_iterator_requirements_helper<T>(0)) {};

template<typename, bool> struct is_iterator_check: std::false_type {};
template<typename T> struct is_iterator_check<T, true>: std::true_type {
    typedef typename std::iterator_traits<T>::difference_type difference_type;
    typedef typename std::iterator_traits<T>::value_type value_type;
    typedef typename std::iterator_traits<T>::iterator_category iterator_category;
    typedef typename std::iterator_traits<T>::reference reference;
    typedef typename std::iterator_traits<T>::pointer pointer;
    static_assert(std::is_same<decltype(*std::declval<T &>()), reference>::value
        || std::is_void<reference>::value, "*r must be of type reference");
};
template<typename T> struct is_iterator: is_iterator_check<T,
    (std::is_pointer<T>::value
     && !std::is_void<typename std::remove_pointer<T>::type>::value
     && !std::is_function<typename std::remove_pointer<T>::type>::value
     ) || (std::is_copy_constructible<T>::value
     && std::is_copy_assignable<T>::value
     && std::is_nothrow_destructible<T>::value
     // TODO: check lvalues are swappable
     && has_iterator_requirements<T>::value
     )> {};

嘗試使用iterator_traits的問題在於它是為所有類型定義的模板,並且其實例化將在非SFINAE上下文中失敗(回想一下SFINAE僅適用於直接替換失敗)。 libstdc ++具有一致的擴展 ,通過在非迭代器類型上實例化iterator_traits將產生一個空類型; 你可以通過檢查類型上是否存在iterator_category來做類似的技巧:

template<typename T> std::true_type has_iterator_category_helper(
    T::iterator_category *);
template<typename T> std::false_type has_iterator_category_helper(...);
template<typename T> struct has_iterator_category<T>:
    decltype(has_iterator_category_helper<T>(0)) { };
template<typename T> struct is_iterator: std::integral_constant<bool,
    std::is_pointer<T>::value || has_iterator_category<T>::value> {};

template<typename T, typename = std::enable_if<is_iterator<T>::value>>
    MyClass(T);

但是,這對於那些本身不公開iterator_category但已經通過單獨的iterator_traits進行調整的類型不起作用 ; 在這種情況下,簡單的SFINAE方法更有意義(並且您可以在構造函數中實例化iterator_traits以確認類型是類迭代器)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM