C++模板技术探究仿函数、适配器、模板特化
模板技术
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的成员函数,那么断言就会通过,如果不存在这两个函数,断言就不会通过。
- STL运用的C++技术(2)——模板特化
- C++模板之隐式实例化、显示实例化、隐式调用、显示调用和模板特化详解
- 【C++标准模板库笔记1】C++的模板技术
- C++ 模板类型萃取技术
- 第2章 C++模板技术
- STL运用的C++技术(1)——成员模板
- STL运用的C++技术(1)——成员模板
- C++ 模板 之 类型萃取 与 容器适配器
- C++ 模板及模板特化
- C++的模板及模板特化
- 利用C++模板技术支持多种计算策略
- C++模板技术在共享内存中的应用
- STL运用的C++技术(2)——模板特化
- C++模板与泛型(3.模板特化)
- C++模板及模板特化
- C++ 模板 之 类型萃取 与 容器适配器
- STL运用的C++技术(3)——模板实参推断
- STL运用的C++技术(2)——模板特化
- C++模板实战4:模板特化
- C++模板(5) - 模板特化