【问题标题】:Function template accepting only non integral types (specifially bidirectional iterators)仅接受非整数类型的函数模板(特别是双向迭代器)
【发布时间】:2021-12-26 03:55:52
【问题描述】:

如果参数是我创建的迭代器,我需要一个只接受非整数类型的函数模板(我创建了自己的类并使用 enable_if 和一个标签,我设法推断出参数是否是我创建的迭代器或不是)

template <typename InputIterator>
        foo (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type(),
        typename ft::enable_if<InputIterator::InputIter, InputIterator>::type = NULL)
        {
            insert(begin(), first, last);
        }

我想确保传递给函数的参数是我自己的迭代器或双向迭代器,但是我认为如果我可以检查“InputIterator”是否只是非整数但我不知道这会容易得多实现它需要什么,我不确定它是否是一个好主意,因为归根结底,我真正需要的是确保它是一个符合我标准的迭代器。

我应该如何进行?哪些功能值得研究?

我正在使用 -std=c++98,所以我坚持使用 c++98 库,所以没有 c++11 或 98 之后出现的任何功能。

【问题讨论】:

  • 也许完全删除 SFINAE?如果将“双向迭代器”近似为您可以接受的“非整数”,为什么首先需要它? "am using -std=c++98" :/ 你真的应该升级。甚至 std::is_integral 也是 C++11 的特性。
  • @HolyBlackCat 它是学校项目的一部分,由于该主题,仅限于 c++ 98,我重新制作了自己的 enable_if 和 is_integral 但我只是在我无法确定的领域缺乏知识其余的功能,一些答案提到了很多我以前不知道的东西,它看起来很有帮助,所以我认为它在 98 上是可行的,我将尝试实现我学到的东西,如果它有效,分享解决方案(如果有人有一天类似的问题)
  • “学校项目的一部分”。那么你可能想多了。 “使用 C++98”和“重新制作 C++>=11 的部分”是此类项目中几乎不会同时存在的两个要求。

标签: c++ stl iterator c++98


【解决方案1】:

您可以自己创建一些类型特征来获得 SFINAE。

由于它是 C++98,您可以从创建一些包含在较新标准中的特征开始:

template<class T, class U>
struct is_same { static const bool value; };
template<class T, class U> const bool is_same<T,U>::value = false;
 
template<class T>
struct is_same<T, T> { static const bool value; };
template<class T> const bool is_same<T,T>::value = true;

template<bool B, class T = void> struct enable_if {};
 
template<class T> struct enable_if<true, T> { typedef T type; };

然后你可以建立自己的特质:

template<class It>
struct accepted_iterator {
    static const bool value;
};

#include <iterator>
template<class It>
const bool accepted_iterator<It>::value = // add the accepted iterator categories here:
    is_same<typename std::iterator_traits<It>::iterator_category,
                   std::bidirectional_iterator_tag>::value ||
    is_same<typename std::iterator_traits<It>::iterator_category,
                   std::random_access_iterator_tag>::value;

并检查迭代器类型,SFINAE 样式:

template <typename InputIterator>
typename enable_if<accepted_iterator<InputIterator>::value>::type
foo (InputIterator first, InputIterator last) {

}

【讨论】:

    【解决方案2】:

    由于您仅限于 C++98,因此最好尝试更新版本中提供的动画 SFINAE 工具c++03。这样代码对于未来的维护者来说会更加熟悉。

    例如C++98没有以下工具:std::enable_ifstd::iterator_traitsstd::is_integral

    你的情况很简单,所以不难,但需要大量的样板:

    #include <numeric>
    
    template <typename T>
    struct is_integer {
        static const bool value = false;
    };
    
    template <>
    struct is_integer<int> {
        static const bool value = true;
    };
    
    template <>
    struct is_integer<char> {
        static const bool value = true;
    };
    
    template <>
    struct is_integer<long int> {
        static const bool value = true;
    };
    
    template <>
    struct is_integer<unsigned int> {
        static const bool value = true;
    };
    
    template <>
    struct is_integer<unsigned char> {
        static const bool value = true;
    };
    
    template <>
    struct is_integer<unsigned long int> {
        static const bool value = true;
    };
    
    template <bool codition, typename T = void>
    struct enable_if {};
    
    template <typename T>
    struct enable_if<true, T> {
        typedef T type;
    };
    
    template <typename T>
    struct iterator_traits {
        typedef typename T::value_type value_type;
    };
    
    template <typename T>
    struct iterator_traits<T*> {
        typedef T value_type;
    };
    
    template <typename InputIterator>
    typename enable_if<
            is_integer<
                    typename iterator_traits<InputIterator>::value_type
                >::value,
            typename iterator_traits<InputIterator>::value_type
        >::type
    foo(InputIterator first, InputIterator last) {
        typedef typename iterator_traits<InputIterator>::value_type type;
        return std::accumulate(first, last, type(0));
    }
    
    void test() {
        int arr[3] = {1, 3, 4};
        foo(arr, arr + 3);
    }
    
    #ifdef TEST_FAILURE
    void test_faiure() {
        double arr[3] = {1, 3, 4};
        foo(arr, arr + 3);
    }
    #endif
    

    live demosmall improvment

    我没有检查 C++98 的 boost 状态是什么(尤其是你没有指定编译器),但你应该检查这是否已经在那里完成以及它是否可以被你的编译器使用。

    【讨论】:

    • 我认为iterator_traits 在 C++98 中。这是 your code 使用 std::iterator_traits 代替。
    • @TedLyngmo 很酷。在验证代码时我不得不搞砸一些东西,并且未能找到适合 C++98 的文档。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 1970-01-01
    • 2016-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多