您的位置:首页 > 编程语言 > C语言/C++

C++模板技术探究仿函数、适配器、模板特化

2020-08-26 16:58 1171 查看

模板技术

  • 适配器
  • 模板特化(void_t使用)
  • C++中算法无非是传入
    (1)迭代器
    (2)仿函数(适配器)

    仿函数

    仿函数主要时进行算法调用自定函数的用途。
    我们来实现仿函数的时候,尽可能包含下面这三个类型定义:
    因为他是和适配器之间结合的桥梁,当函数对象与适配器接口的时候,适配器需要询问这三个问题,如果不存在这三个类型定义,那么该仿函数会变得很不灵活,不能与适配器进行结合使用。

    typedef _Ty first_argument_type;
    typedef _Ty second_argument_type;
    typedef bool result_type;

    支持的算法有:

    accumulate(累积和)

    template<typename _InputIterator, typename _Tp, typename _BinaryOperation>
    inline _Tp
    accumulate(_InputIterator __first, _InputIterator __last, _Tp __init,
    _BinaryOperation __binary_op)
    {
    // concept requirements
    __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
    __glibcxx_requires_valid_range(__first, __last);
    
    for (; __first != __last; ++__first)
    __init = __binary_op(__init, *__first);
    return __init;
    }

    inner_product(内积)

    template<typename _InputIterator1, typename _InputIterator2, typename _Tp,
    typename _BinaryOperation1, typename _BinaryOperation2>
    inline _Tp
    inner_product(_InputIterator1 __first1, _InputIterator1 __last1,
    _InputIterator2 __first2, _Tp __init,
    _BinaryOperation1 __binary_op1,
    _BinaryOperation2 __binary_op2)
    {
    // concept requirements
    __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>)
    __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>)
    __glibcxx_requires_valid_range(__first1, __last1);
    
    for (; __first1 != __last1; ++__first1, (void)++__first2)
    __init = __binary_op1(__init, __binary_op2(*__first1, *__first2));
    return __init;
    }

    partial_sum(前 N 项和)

    template<typename _InputIterator, typename _OutputIterator,
    typename _BinaryOperation>
    _OutputIterator
    partial_sum(_InputIterator __first, _InputIterator __last,
    _OutputIterator __result, _BinaryOperation __binary_op)
    {
    typedef typename iterator_traits<_InputIterator>::value_type _ValueType;
    
    // concept requirements
    __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
    __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator,
    _ValueType>)
    __glibcxx_requires_valid_range(__first, __last);
    
    if (__first == __last)
    return __result;
    _ValueType __value = *__first;
    *__result = __value;
    while (++__first != __last)
    {
    __value = __binary_op(__value, *__first);
    *++__result = __value;
    }
    return ++__result;
    }

    这里只是列举例子说明仿函数,更多的算法可以参照C++源码。

    适配器

    适配器是算法和仿函数之间的桥梁,它本身也是一种仿函数,只不过可以灵活的通过适配器来更改仿函数形成新的函数效果。下面举两个例子:
    这个例子是将二元仿函数的第一个参数绑定成固定的值,可以用来判断是否大于某个值或者是否等于某个值。
    继承了unary_function,该类主要是进行了类型的重定义,即记录一元函数的参数类型和返回值类型,二元函数进行绑定之后,就变成了一元参数,只能传入一个参数了,因此记录该类型,并进行固定第二个参数值的记录。调用时第一个参数传入仿函数对象

    count_if (arr3, arr3 + size, bind2nd(less<int>(), 11))
    template<class _Arg,
    class _Result>
    struct unary_function
    {	// base class for unary functions
    typedef _Arg argument_type;
    typedef _Result result_type;
    };
    template<class _Fn>
    class binder1st
    : public unary_function<typename _Fn::second_argument_type,
    typename _Fn::result_type>
    {	// functor adapter _Func(stored, right)
    public:
    typedef unary_function<typename _Fn::second_argument_type,
    typename _Fn::result_type> _Base;
    typedef typename _Base::argument_type argument_type;
    typedef typename _Base::result_type result_type;
    
    binder1st(const _Fn& _Func,
    const typename _Fn::first_argument_type& _Left)
    : op(_Func), value(_Left)
    {	// construct from functor and left operand
    }
    
    result_type operator()(const argument_type& _Right) const
    {	// apply functor to operands
    return (op(value, _Right));
    }
    
    result_type operator()(argument_type& _Right) const
    {	// apply functor to operands
    return (op(value, _Right));
    }
    
    protected:
    _Fn op;	// the functor to apply
    typename _Fn::first_argument_type value;	// the left operand
    };

    模板特化(void_t使用)

    先来看看void_t的定义。

    template<class... _Types>
    using void_ttt = void;

    下面是模板库中使用void_t的例子,其实是模板特化的使用。
    如果某个迭代器能够回答出下面这几个东西,编译器就会调用第二个结构体,如果回答不上来,编译器就会调用上面那个结构体。void_ttt本身与void没有什么不同,只不过通过变参模板机制来更好的实现模板特化。那么它还有什么用呢?用来写一个静态断言是很简单的事情啦!!在后面

    typename _Iter::iterator_category,
    typename _Iter::value_type,
    typename _Iter::difference_type,
    typename _Iter::pointer,
    typename _Iter::reference

    template<class,
    class = void>
    struct _Iterator_traits_base1
    {	// empty for non-iterators
    void display()
    {
    cout<<"我是不带的"<<endl;
    }
    };
    
    template<class _Iter>
    struct _Iterator_traits_base1<_Iter, void_ttt<
    typename _Iter::iterator_category,
    typename _Iter::value_type,
    typename _Iter::difference_type,
    typename _Iter::pointer,
    typename _Iter::reference
    >>
    {	// defined if _Iter::* types exist
    using iterator_category = typename _Iter::iterator_category;
    using value_type = typename _Iter::value_type;
    using difference_type = typename _Iter::difference_type;
    
    using pointer = typename _Iter::pointer;
    using reference = typename _Iter::reference;
    void display()
    {
    cout<<"我是带的"<<endl;
    }
    };

    下面我们来看用void_t结合模板特化来实现静态断言的机制

    template <typename T, typename = void>
    struct RangeConcept : std::false_type {};
    
    template <typename T>
    struct RangeConcept<T,
    std::void_t<
    decltype(  std::declval<T >().begin() ),
    decltype(  std::declval<T >().end() )
    >
    >
    : std::true_type {};
    
    template<typename Cont>
    void show( Cont c){
    static_assert( RangeConcept< Cont >::value, "must be a range. means.. it has begin() and end()" );
    }int main() {    int a = 10; std::vector<int> vec{1,2,3,4,5}; show(vec);
    _Iterator_traits_base1<int> it;
    it.display();
    }

    这个文件使用来实现静态断言的,也就是如果某个对象它存在
    begin和end的成员函数,那么断言就会通过,如果不存在这两个函数,断言就不会通过。

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: