关于 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,但我无法弄清楚它是如何工作的以及为什么工作。
- 为什么这段代码使用两个模板?
class U
模板有什么作用?
_test(...)
是函数还是构造函数? (...)
是什么意思?
2-1.如果 _test
是函数,这段代码是否在做函数重载?那么如何用不同的 return 类型重载?
2-2。如果 _test
是构造函数,那么 char
是 c++ 中的 class 吗?
* =
运算符在 (typename U::iterator_category * = 0)
中做什么?它是乘以 iterator_category
还是使 iterator_category
指针为 0?
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.
我正在研究迭代器,我在 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,但我无法弄清楚它是如何工作的以及为什么工作。
- 为什么这段代码使用两个模板?
class U
模板有什么作用? _test(...)
是函数还是构造函数?(...)
是什么意思?
2-1.如果_test
是函数,这段代码是否在做函数重载?那么如何用不同的 return 类型重载?
2-2。如果_test
是构造函数,那么char
是 c++ 中的 class 吗?* =
运算符在(typename U::iterator_category * = 0)
中做什么?它是乘以iterator_category
还是使iterator_category
指针为 0?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.