关于 iterator_traits 的 c++ 模板结构

c++ template structure about iterator_traits

我正在研究迭代器,我在 github.
上找到了一些源代码 我知道这段代码的作用,但找不到方法。


    template <class T>
    struct _has_iterator_category
    {
    private:
        struct _two { char _lx; char _lxx; };
        template <class U>  static _two _test(...);
        template <class U>  static char _test(typename U::iterator_category * = 0);
    public:
        static const bool value = sizeof(_test<T>(0)) == 1;
    };

我认为这段代码会检查 T 是否有 iterator_category,但我无法弄清楚它是如何工作的以及为什么工作。

  1. 为什么这段代码使用两个模板? class U 模板有什么作用?
  2. _test(...)是函数还是构造函数? (...) 是什么意思?
    2-1.如果 _test 是函数,这段代码是否在做函数重载?那么如何用不同的 return 类型重载?
    2-2。如果 _test 是构造函数,那么 char 是 c++ 中的 class 吗?
  3. * = 运算符在 (typename U::iterator_category * = 0) 中做什么?它是乘以 iterator_category 还是使 iterator_category 指针为 0?
  4. sizeof(_test<T>(0)) == 1; 是什么意思?如果 sizeof(_test<T>(0)) 为 1,是否 return 为真?

我搜索了很多文档 iterator_traits 和其他东西,但未能解释这段代码。

首先,这段代码本身是完全可解释的,如果你懂 C++。不需要有关外部组件的文档。它不依赖于任何东西。您提出的问题表明在基本 C++ 语法理解方面存在一些差距。

1. 模板定义 _test 是 class 模板 _has_iterator_category 的模板成员。它是在模板中定义的模板,所以即使你实例化_has_iterator_category,你仍然需要稍后实例化_test,它有一个单独的模板参数。

2. 从技术上讲,两者都不是。因为 class 模板不是类型,函数模板(_test 是类型)不是函数。

构造函数的名称 总是 匹配最嵌套的封闭 class 作用域,即此处的 _has_iterator_category_has_iterator_category 没有声明构造函数。

函数模板。有两个模板,用于不同的参数,具有不同的参数类型。如果两个模板都可以通过用具体类型成功替换 U 来实例化,则函数 重载。

3. 不是运算符* =,运算符中不能有空格。是 *=。这是参数列表的无名版本,可以用其他方式编写:

template <class U>  static char _test(typename U::iterator_category *arg = 0);

= 0 是函数参数的默认值 arg。由于在此上下文中未使用 arg,因此可以跳过其名称。

函数签名的单个参数的类型为U::iterator_category *typename 是大多数但最新的 C++ 标准要求的关键字,用于依赖于模板参数的嵌套类型。这假定 U 必须具有嵌套类型 iterator_category。否则模板参数替换会失败。

template <class U>  static _two _test(...);

这里的函数签名是“variadic”。这意味着函数在替换模板参数后可以接受任意数量的参数。 Just like printf.

4. sizeof(_test<T>(0)) == 1 等于 true 如果 _test<T>(0) 结果的大小等于 1.

整个结构是一种称为 SFINAE 的规则形式 - 替换失败不是错误。即使编译器无法替换一个候选者,它仍会尝试其他候选者。当所有选项都用尽时,将诊断出错误。

在这种情况下,表达式 sizeof(_test<T>(0)) 试图用 T 替换 U。这就是为什么 _test 被做成嵌套模板的原因。 class 有效,但现在我们检查函数。

如果 type-id T::iterator_category 有效,则替换将成功,因为生成的声明将有效。 _test(...)也可以成功,但是接下来我们要重载选择规则。

可变参数总是意味着类型转换,因此没有歧义,_test(...) 将被丢弃。

如果 T::iterator_category 不是有效类型,_two _test(...)_test() 的唯一实例。

假设 sizeof(char) 等于 1,常量 value 初始化为 true if return expression 的值将是 _test<T>(0) got same size作为 char。仅当 T::iterator_category 存在时才成立。

本质上,如果 class T 以有些笨拙和过时的方式包含嵌套类型 T::iterator_category,则此结构会进行检查。但它与早期的 C++ 标准兼容,因为它不使用 nullptr<type_traits> header.