Overloaded resolution(多载化决议程序)

本文探讨了C++ STL中的多载化决议技术,通过模板函数和标记参数实现根据不同迭代器类型选择正确行为。重点讲解了input_iterator_tag, output_iterator_tag等tag的使用以及__iterator_traits和__advance函数的trait机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多载化决议是在STL(Standard Library)实现中的一种技术,例如有多个同名函数实现相似的功能,甚至参数列表难以区分(考虑模板函数)。要区分这些函数使得编译通过,修改函数名不是一种好方法,更好的方法是设置过个标记,增加一个参数接收标记,通过标记来决定用哪个函数。代码示例如下

#include<iostream>
using namespace std;

struct T1{};
struct T2 :T1 {};
struct T3 {};


void f(T1)
{
	cout << "T1\n";
	return;
}
/*
void f(T2)
{
	cout << "T2\n";
	return;
}
*/

void f(T3)
{
	cout << "T3\n";
	return;
}

int main()
{
	f(T2());
	f(T3());
	return 0;
}

这里会输出

T1

T3

这里T2继承T1,所以对T2的调用转到了对T1的调用。但是如果把注释取消,则会输出T2.

在/bits/stl_iterator_base_types.h中有如下tag定义。

struct input_iterator_tag { };

 ///  Marking output iterators.
  struct output_iterator_tag { };

 /// Forward iterators support a superset of input iterator operations.
  struct forward_iterator_tag : public input_iterator_tag { };

  /// Bidirectional iterators support a superset of forward iterator
  /// operations.
  struct bidirectional_iterator_tag : public forward_iterator_tag { };

  /// Random-access iterators support a superset of bidirectional
  /// iterator operations.
  struct random_access_iterator_tag : public bidirectional_iterator_tag { };

在STL中定义迭代器的前进函数需要多载化决议技术,先看一些宏,在MingGW\mingw64\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\bits\concept_check.h中


#ifndef _CONCEPT_CHECK_H
#define _CONCEPT_CHECK_H 1

#pragma GCC system_header

#include <bits/c++config.h>


#if !defined(_GLIBCXX_CONCEPT_CHECKS) || !_GLIBCXX_HOSTED

#define __glibcxx_function_requires(...)
#define __glibcxx_class_requires(_a,_b)
#define __glibcxx_class_requires2(_a,_b,_c)
#define __glibcxx_class_requires3(_a,_b,_c,_d)
#define __glibcxx_class_requires4(_a,_b,_c,_d,_e)

#else // the checks are on

#include <bits/boost_concept_check.h>


#define __glibcxx_function_requires(...)                                 \
            __gnu_cxx::__function_requires< __gnu_cxx::__VA_ARGS__ >();
#define __glibcxx_class_requires(_a,_C)                                  \
            _GLIBCXX_CLASS_REQUIRES(_a, __gnu_cxx, _C);
#define __glibcxx_class_requires2(_a,_b,_C)                              \
            _GLIBCXX_CLASS_REQUIRES2(_a, _b, __gnu_cxx, _C);
#define __glibcxx_class_requires3(_a,_b,_c,_C)                           \
            _GLIBCXX_CLASS_REQUIRES3(_a, _b, _c, __gnu_cxx, _C);
#define __glibcxx_class_requires4(_a,_b,_c,_d,_C)                        \
            _GLIBCXX_CLASS_REQUIRES4(_a, _b, _c, _d, __gnu_cxx, _C);

#endif // enable/disable

#endif // _GLIBCXX_CONCEPT_CHECK

在我的配置中上面的宏都是空. MingGW\mingw64\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\bits\stl_iterator_base_funcs.h中有如下代码

template<typename _InputIterator, typename _Distance>
    inline _GLIBCXX14_CONSTEXPR void
    __advance(_InputIterator& __i, _Distance __n, input_iterator_tag)
    {
      // concept requirements
      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
      __glibcxx_assert(__n >= 0);
      while (__n--)
	++__i;
    }

template<typename _BidirectionalIterator, typename _Distance>
    inline _GLIBCXX14_CONSTEXPR void
    __advance(_BidirectionalIterator& __i, _Distance __n,
	      bidirectional_iterator_tag)
    {
      // concept requirements
      __glibcxx_function_requires(_BidirectionalIteratorConcept<
				  _BidirectionalIterator>)
      if (__n > 0)
        while (__n--)
	  ++__i;
      else
        while (__n++)
	  --__i;
    }

template<typename _RandomAccessIterator, typename _Distance>
    inline _GLIBCXX14_CONSTEXPR void
    __advance(_RandomAccessIterator& __i, _Distance __n,
              random_access_iterator_tag)
    {
      // concept requirements
      __glibcxx_function_requires(_RandomAccessIteratorConcept<
				  _RandomAccessIterator>)
      if (__builtin_constant_p(__n) && __n == 1)
	++__i;
      else if (__builtin_constant_p(__n) && __n == -1)
	--__i;
      else
	__i += __n;
    }

3个同名模板函数依靠tag参数区分,都是使迭代器移动n个位置。_InputIterator只能每次前进1个单位,_BidirectionalIterator每次可以前进或后退1个单位,_RandomAccessIterator则可以随机访问。使用advance函数时当然只有参数__i, __n是必要的,期望tag参数能自动判断。这个自动判断机制叫做traits,就是提取类型的特性。这个traits机制也是用模板类实现,并且用到了partial specialization,其实就是某些特殊情况特殊处理。

template<typename _Iterator, typename = __void_t<>>
    struct __iterator_traits { };

  template<typename _Iterator>
    struct __iterator_traits<_Iterator,
			     __void_t<typename _Iterator::iterator_category,
				      typename _Iterator::value_type,
				      typename _Iterator::difference_type,
				      typename _Iterator::pointer,
				      typename _Iterator::reference>>
    {
      typedef typename _Iterator::iterator_category iterator_category;
      typedef typename _Iterator::value_type        value_type;
      typedef typename _Iterator::difference_type   difference_type;
      typedef typename _Iterator::pointer           pointer;
      typedef typename _Iterator::reference         reference;
    };

  template<typename _Iterator>
    struct iterator_traits
    : public __iterator_traits<_Iterator> { };

/// Partial specialization for pointer types.
  template<typename _Tp>
    struct iterator_traits<_Tp*>
    {
      typedef random_access_iterator_tag iterator_category;
      typedef _Tp                         value_type;
      typedef ptrdiff_t                   difference_type;
      typedef _Tp*                        pointer;
      typedef _Tp&                        reference;
    };

  /// Partial specialization for const pointer types.
  template<typename _Tp>
    struct iterator_traits<const _Tp*>
    {
      typedef random_access_iterator_tag iterator_category;
      typedef _Tp                         value_type;
      typedef ptrdiff_t                   difference_type;
      typedef const _Tp*                  pointer;
      typedef const _Tp&                  reference;
    };

__void_t<...>定义为void,所以前面一大段都可以忽略。制定STL迭代器的时候都应该指定iterator_category; value_type; difference_type; pointer; reference;

这些不是变量,对编译器来说只是名称的代换。而基本类型像int没有这5个名词的定义,但是它的迭代器如int *会根据partial specialization得到这5个名词。

最后把__advance函数包装起来,

template<typename _InputIterator, typename _Distance>
    inline _GLIBCXX17_CONSTEXPR void
    advance(_InputIterator& __i, _Distance __n)
    {
      // concept requirements -- taken care of in __advance
      typename iterator_traits<_InputIterator>::difference_type __d = __n;
      std::__advance(__i, __d, std::__iterator_category(__i));
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值